• 1. 二维数组中的查找
  • 2. 替换空格
  • 3.从尾到头打印链表
  • 4.重建二叉树
  • 5.用两个栈实现队列
  • 6. 旋转数组的最小值
  • 7. 斐波那契数列
  • 8. 跳台阶
  • 9. 变态跳台阶
  • 10. 矩阵覆盖
  • 11. 二进制中1的个数
  • 12. 数值的整数次方
  • 13. 调整数组顺序使奇数位于偶数前面
  • 14.链表中倒数第k个结点
  • 15.反转链表
  • 16.合并两个排序的链表
  • 17.树的子结构
  • 18. 二叉树的镜像
  • 19. 顺时针打印矩阵
  • 20.包含min函数的栈
  • 21. 栈的压入弹出序列
  • 22.从上往下打印二叉树
  • 23.二叉搜索树的后序遍历序列
  • 24.二叉树中和为某个值的路径
  • 25.复杂链表的复制
  • 28. 数组中出现次数超过一半的数字
  • 29. 最小的K个数
  • 30. 连续子数组的最大和
  • 33. 丑数
  • 34. 第一个只出现一次的字符
  • 40. 数组中只出现一次的数字
  • 41. 和为s的连续正数序列
  • 47.求1+2+3+…+n
  • 65.矩阵中的路径
  • 66.机器人的运动范围


1. 二维数组中的查找

-*- coding:utf-8 -*-
'''
题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
测试用例:
1)二维数组中包含查找的数字(查找的数字是数组中的最大值和最小值,查找的数字介于数值中的最大值和最小值之间)。
2)二维数组中没有查找的数字(查找的数字大于数组中的最大值,查找的数字小于数组中的最小值,查找的数字在最大最小值之间但数组没有这个数字)
3)特殊输入测试(输入空指针)
'''
#思路一:普通循环遍历
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        length = len(array)
        condition = 0
        for num in range(length):
            if target in array[num]:
                print('true')
                condition = 1
                break
        if condition == 0:
            print('false')

#思路二:优化遍历方法.从左下角开始查找,当要查找数字比左下角数字大时。右移.要查找数字比左下角数字小时,上移.
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        height = len(array)
        width = len(array[0])
        h = height - 1
        w = 0
        if height * width == 0:
            print('false')
        else:
            for i in range(height * width):
                if w == width or h == -1:
                    print('false')
                    break
                if target == array[h][w]:
                    print('true')
                    break
                elif target > array[h][w]:
                    w = w + 1
                elif target < array[h][w]:
                    h = h - 1

2. 替换空格

# -*- coding:utf-8 -*-
'''
题目:请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
测试用例:
1)字符串里没有空格
2)字符串里有空格(空格位于最前面,最后面,中间,连续出现)
3)特殊输入测试:字符串为空字符串,为NULL(None),字符串里只有一个空格字符,字符串中只有连续多个空格
注:在Python中,字符串是不可变类型,即无法直接修改字符串的某一位字符。也就是说s[i] = '%20'这种赋值语句是错的。因此改变一个字符串的元素需要新建一个新的字符串。
'''
#############如果允许用replace############
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        if s == None:
            return 0
        # print(s.replace(' ','%20'))
        return s.replace(' ','%20')
#############如果不允许用replace, 可以给一个新字符赋值##############
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        if s == None:
            return 0
        length = len(s)
        # print(length)
        new_s = ''
        for i in range(length):
            # print(s[i])
            if s[i] == ' ':
                new_s += '%20'
            else:
                new_s += s[i]
        # print(new_s)
        return new_s

#############如果不允许用replace,可以将字符串转换成列表后修改值,然后用join组成新字符串##############
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        if s == None:
            return 0
        s = list(s)
        for i in range(len(s)):
            if s[i] == ' ':
                s[i] = '%20'
        s=''.join(s)
        # print(s)
        return s

3.从尾到头打印链表

# -*- coding:utf-8 -*-
'''
题目:输入一个链表,从尾到头打印链表每个节点的值。
测试用例:
1)正常链表,只有一个节点,有很多节点
2)特殊输入,输入为None
'''
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
##############用insert得到一个从尾到头的列表#####
#inset会把元素插在我们指定的位置,但是这样的话列表指定位置后面的值都要向后移一位,感觉效率不会很高
class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        l = []
        head = listNode
        while head:
            l.insert(0, head.val)
            head = head.next
        return l
###############用append得到一个从尾到头的列表#####
#牺牲空间换时间
class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        l = []
        new_l = []
        head = listNode
        while head:
            l.append(head.val)
            head = head.next
        while l:
            new_l.append(l.pop())
        return new_l

4.重建二叉树

# -*- coding:utf-8 -*-
'''
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
测试用例:
1)普通二叉树(完全二叉树,不完全二叉树)
2)特殊二叉树(所有结点都没有右子结点的二叉树,所有结点都没有左子结点的二叉树,只有一个结点的二叉树)
3)特殊用例,输入为空,输入的前序和中序序列不匹配(长度不同数字不同)
思路:
前序遍历的第一个值是根节点。中序遍历中根节点的左右分别为左右子树的节点。前序遍历的第二个值是左子树的根节点,第一个右子树节点是右子树的根节点。按照这个方法递归就可以重建二叉树
'''
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if len(pre) != len(tin):
            raise AttributeError('{} must equal {}'.format(pre, tin))
        if len(pre) == 1:
            if pre == tin:
                return TreeNode(pre[0])
            else:
                raise AttributeError('{} must equal {}'.format(pre, tin))
        if len(pre) == 0:
            return None
        if len(pre) == 1:
            return TreeNode(pre[0])
        else:
            root_node = TreeNode(pre[0])
            root_node.left = self.reConstructBinaryTree(pre[1:tin.index(pre[0])+1],tin[:tin.index(pre[0])])
            root_node.right = self.reConstructBinaryTree(pre[tin.index(pre[0])+1:],tin[tin.index(pre[0])+1:] )
        return root_node
pre = [1,2,4,7,3,5,6,8]
tin = [4,7,2,1,5,3,8,6]
target = Solution()
root_node = target.reConstructBinaryTree(pre,tin)

5.用两个栈实现队列

# -*- coding:utf-8 -*-
'''
题目:用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型
测试用例:
1)往空的队列里添加,删除元素
2)往非空的队列里添加,删除元素
3)连续删除元素直至队列为空
4)特殊用例,输入为None,队列里没东西还要pop
思路:栈是先入后出,队列是先入先出。也就是说一个序列依次入一个栈再出一个栈就等同于经过了一个队列操作。
可以用一个栈(stack1)专门接收输入(push),然后另一个栈(stack2)专门负责输出(pop)。
每次输出前检查stack2,如果stack2里没有东西,而stack1里有东西,把stack1里的pop到stack2里,再输出stack2里的东西。
如果stack2里本身就有,那直接输出stack2就可以了。
'''
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self, node):
        # write code here
        if node == None:
            raise AttributeError('no input')
        self.stack1.append(node)
    def pop(self):
        if self.stack2 == []:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        if self.stack2 == []:
            raise AttributeError('queue is empty')
        return self.stack2.pop()

6. 旋转数组的最小值

# -*- coding:utf-8 -*-
'''
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。给出的所有元素都大于0,若数组大小为0,请返回0。
测试用例:
1)一个元素各异的旋转数组
2)一个有相同元素的数组(两个或以上元素相同)
3)特殊用例,一个空数组,一个只有一个元素的数组,一个旋转为0的数组(递增的数组)
思路:因为是个非递减排序的旋转,所以最小元素刚好是两段子数组的分界线,且第一段子数组的所有元素都大于等于第二段子数组,两段数组内都是非递减的。
所以我们可以从中间元素开始找,如果中间元素大于总数组的第一个元素(第一段数组的段首),则中间元素在第一段数组里,且最小在它后面,可以把搜索范围缩小为中间元素到总数组末尾。
如果中间元素小于总数组的最后一个元素(第二段数组的段尾),则中间元素在第二段数组里,且最小在它前面,可以把搜索范围缩小为总数组第一个元素到中间元素。
然后我们在缩小的范围内继续重复这样的思想,最终会得到相邻的两个元素,后一个就是旋转数组的最小元素。
如果第一个元素,最后一个元素与中间元素相同,则缩小不了范围,需要顺序查找。如果数组并没有旋转,那第一个元素会小于最后一个元素,直接返回第一个元素即可
'''
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        length = len(rotateArray)
        if length == 0:
            return 0
        elif length == 1:
            return rotateArray[0]
        elif rotateArray[0] < rotateArray[-1]:
            return rotateArray[0]
        else:
            begin_index  = 0
            mid_index = length/2
            end_index  = length-1
            while len(rotateArray[begin_index : end_index +1]) != 2:
                if rotateArray[mid_index] > rotateArray[begin_index] :
                    begin_index = mid_index
                    mid_index = (end_index + begin_index )/2
                elif rotateArray[mid_index] < rotateArray[end_index]:
                    end_index = mid_index
                    mid_index = (end_index + begin_index )/2
                else:
                    min_num = rotateArray[begin_index]
                    for i in range(begin_index,end_index + 1):
                        if rotateArray[i] < min_num:
                            min_num = rotateArray[i]
                    return min_num
            return rotateArray[end_index]

7. 斐波那契数列

# -*- coding:utf-8 -*-
'''
题目:输入一个整数n,请你输出斐波那契数列的第n项。n<=39.斐波那契数列1,1,2,3,5,8....F(n)=F(n-1)+F(n-2)
测试用例:
1)n>=2
2)n = 0,n = 1
思路:求第n项直接用递归返回f(n-1)+f(n-2)很容易,但是会有很多重复计算,算f(n)会用到f(n-1),f(n-2),算f(n-1)会用到f(n-2),f(n-3),这个过程中f(n-2)就算了两次。
为了提高时间效率,我们可以从第0项开始往上找,直到找到第n项,把已经得到的数列中间项保存起来,这样前面计算过的就不用重复计算了。
也就是说,设定两个变量,num1为前一项的值,num2为当前项的值。下一项就是num1+num2。把当前项的值放到num1里,把下一项的值放到num2,这样就往后算了一项。通过循环就能得到第n项。
'''
class Solution:
    def Fibonacci(self, n):
        # write code here
        if n == 0:
            return(0)
        elif n == 1 or n == 2:
            return(1)
        else:
            num1 = 1
            num2 = 1
            for n in range(n-2):
                # temp = num2
                # num2 = num1 + num2
                # num1 = temp
                num2 = num1 + num2
                num1 = num2 - num1
            return(num2)

8. 跳台阶

# -*- coding:utf-8 -*-
'''
题目:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
测试用例:
1)只跳一级或者两级
2)跳多级
思路:斐波那契数列的变形,第二项不同,方法一样的
'''
class Solution:
    def jumpFloor(self, number):
        # write code here
        if number == 1:
            return(1)
        elif number == 2:
            return(2)
        else:
            floor1 = 1
            floor2 = 2
            for n in range(number - 2):
                floor2 = floor1 + floor2
                floor1 = floor2 - floor1
            return(floor2)

9. 变态跳台阶

# -*- coding:utf-8 -*-
'''
题目:一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路:
也是斐波那契数列的变形,
因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级.
跳1级,剩下n-1级,则剩下跳法是f(n-1)
跳2级,剩下n-2级,则剩下跳法是f(n-2)
所以f(n)=f(n-1)+f(n-2)+...+f(1)
因为f(n-1)=f(n-2)+f(n-3)+...+f(1)
所以f(n)=2*f(n-1)=2^(n-1)*f(1)=2^(n-1) 
'''
class Solution:
    def jumpFloorII(self, number):
        # write code here
        return(2**(number - 1))

10. 矩阵覆盖

# -*- coding:utf-8 -*-
#题目:我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
class Solution:
    def rectCover(self, number):
        # write code here
        if number == 0 or number == 1 or number == 2:
            return(number)
        else:
            rectCover1 = 1
            rectCover2 = 2
            for n in range(number - 2):
                rectCover2 = rectCover1 + rectCover2
                rectCover1 = rectCover2 - rectCover1
            return(rectCover2)

思路(截的别人的图):

30 python 剑指offer 剑指offer python下_二叉树

11. 二进制中1的个数

# -*- coding:utf-8 -*-
'''
题目:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
测试用例:
1)负数
2)正数
3)0
思想:
1)普通方法:可以用1与原整数取与来判定对应位是不是1,因为右移整数会出现负数补进1的情况,所以我们通过左移1来更换判定位置(左移1只会补0),重复这个操作直到所有位置都判定结束。即循环次数等于整数二进制位数
2)更好的方法:整数减去1再与原整数取与操作,会把二进制整数最右边一个1变为0,重复这个操作直到整数为0.即循环次数等于1的个数。因为负数的符号位会对这种判断造成影响,所以负数的话需要先与0xffffffff取与,变成不带符号的数。
'''
##########普通方法########
class Solution:
    def NumberOf1(self, n):
        # write code here
        number_of_1 = 0
        for i in range(0,32):
            if (n & (1 << i)) != 0:
                number_of_1 += 1
        return number_of_1
##########更好的方法########
class Solution:
    def NumberOf1(self, n):
        # write code here
        if n < 0:
            n = n & 0xffffffff
        number_of_1 = 0
        while n:
            number_of_1 += 1
            n = n & (n - 1)
        return number_of_1])

12. 数值的整数次方

# -*- coding:utf-8 -*-
'''
题目:给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
测试用例:底数和指数分别设为正数、负数和零
思路:
1.如果允许使用'**'那就是一行的事。
2.全面考虑
1)如果指数是负数,需要先对指数取绝对值,算出次方后再取倒数。
2)如果底数是0,指数是负数需要单独处理,0的0次方没有意义,输出0或1都可以。
3)不能直接用等号判定两个小数是否相等,因为计算机表示小数(包括float和double)都有误差
4)可以区别用一个变量区别一下代码正确返回的0和错误返回的0
3.为了更高效,可以优化求幂
当n为偶数,a^n =(a^n/2)*(a^n/2)
当n为奇数,a^n = a^[(n-1)/2] * a^[(n-1)/2] * a
可以用右移运算符代替除以2,用求余运算符判定一个数是奇数还是偶数
'''
###############使用'**'############
class Solution:
    def Power(self, base, exponent):
        return(base**exponent)

##############全面但不够高效#######
class Solution:
    def equal(self,num1,num2):
        if abs(num1 - num2) < 0.0000001:
            return 1
        else :
            return 0

    def PowerWithUnsignedExponent(self,base,exponent):
        result = 1.0
        for i in range(exponent):
            result *= base
        return result

    def Power(self, base, exponent):
        invalid = 0
        if self.equal(base,0.0) and exponent < 0 :
            invalid = 1
            return 0
        result = self.PowerWithUnsignedExponent(base,abs(exponent))
        if exponent < 0:
            result = 1.0 / result
        return result

##############全面又高效#######
class Solution:
    def equal(self,num1,num2):
        if abs(num1 - num2) < 0.0000001:
            return 1
        else :
            return 0

    def PowerWithUnsignedExponent(self,base,exponent):
        if exponent == 0:
            return 1
        if exponent == 1:
            return base
        result = self.PowerWithUnsignedExponent(base,exponent >> 1)
        result *= result
        if (exponent & 0x1) == 1:
                result *= base
        return result

    def Power(self, base, exponent):
        invalid = 0
        if self.equal(base,0.0) and exponent < 0 :
            invalid = 1
            return 0
        result = self.PowerWithUnsignedExponent(base,abs(exponent))
        if exponent < 0:
            result = 1.0 / result
        return result

13. 调整数组顺序使奇数位于偶数前面

# -*- coding:utf-8 -*-
'''
题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
测试用例:
1)数组奇偶交替
2)所有偶数出现在奇数前面
3)所有奇数出现在偶数前面
4)NULL或者数组只包含一个数
思路:遍历一遍数组,把奇偶分别存到两个数组里,把两个数组接上。
'''
class Solution:
    def reOrderArray(self, array):
        # write code here
        if array = []:
            return 0
        odd_array =[]
        even_array =[]
        for num in array:
            if num & 0x1 == 0:
                even_array.append(num)
            else:
                odd_array.append(num)
        return(odd_array + even_array)

14.链表中倒数第k个结点

# -*- coding:utf-8 -*-
'''
题目:输入一个链表,输出该链表中倒数第k个结点。
测试用例:
1)空链表
2)k>len或k<1
3)正常输入
思路:
1)可以用两个指针,第一个先走k-1个结点第二个再出发。这样的话第一个走到尾结点时第二个刚好是倒数第k个结点
2)可以把所有的结点存到一个列表里,然后取倒数第k个。
'''
# -*- coding:utf-8 -*-
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    def FindKthToTail(self, head, k):
        pointer1 = head
        pointer2 = head
        if head == None or k < 1:
            return None
        for i in range(k-1):
            if pointer1.next == None:
                return None
            pointer1 = pointer1.next
        while pointer1.next != None:
            pointer1 = pointer1.next
            pointer2 = pointer2.next
        return pointer2

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        l=[]
        while head!=None:
            l.append(head)
            head=head.next
        if k>len(l) or k<1:
            return
        return l[-k]

15.反转链表

# -*- coding:utf-8 -*-
'''
题目:输入一个链表,反转链表后,输出链表的所有元素。
测试用例:
1)空链表
2)只有一个结点
3)常规链表
思路:我们需要定义三个指针,分别指向当前遍历到的结点,它的前一个结点和它的后一个结点,这样才不会导致反转后的链表出现断裂
'''
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if not pHead or not pHead.next:
            return pHead
        last = None
        while pHead:
            tmp = pHead.next
            pHead.next = last
            last = pHead
            pHead = tmp
        return last

16.合并两个排序的链表

# -*- coding:utf-8 -*-
'''
题目:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
测试用例:
1)有一个是空链表,两个都是空链表
2)两个链表中只有一个结点
3)两个链表有多个结点,结点的值互不相同或者存在值相同的多个结点。
思路:比较两个链表的头结点,取小的一个作为合并后链表的头结点。
然后小的一个所在的链表的头结点后移一个。继续对比两个链表的头结点,得出一个小值接到合并后的链表中,递归。
直到其中一个链表已经为空,此时将另一个链表全部接到合并的链表后。
'''
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if pHead1 == None:
            return pHead2
        if pHead2 == None:
            return pHead1
        merge_phead = None
        if pHead1.val < pHead2.val :
            merge_phead = pHead1
            merge_phead.next = self.Merge(pHead1.next,pHead2)
        else:
            merge_phead = pHead2
            merge_phead.next = self.Merge(pHead1,pHead2.next)
        return merge_phead

17.树的子结构

# -*- coding:utf-8 -*-
'''
题目:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
测试用例:
1)有一个为空,两个都为空
2)两个二叉树中只有一个根结点,一棵树只有一个根结点
3)普通二叉树
思路:先在A中找到B的根结点,再分别到左右子树中找相同结构。
'''
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def compare(self, pRoot1, pRoot2):
        if pRoot2 == None:
            return 1
        if pRoot1 == None:
            return 0
        if pRoot1.val !=  pRoot2.val:
            return 0
        return self.compare(pRoot1.left,pRoot2.left) and self.compare(pRoot1.right,pRoot2.right)

    def HasSubtree(self, pRoot1, pRoot2):
        result = 0
        if  pRoot1 != None and pRoot2 != None:
            if pRoot1.val == pRoot2.val:
                result = self.compare(pRoot1,pRoot2)
            if result == 0:
                result = self.HasSubtree(pRoot1.left,pRoot2)
            if result == 0:
                result = self.HasSubtree(pRoot1.right,pRoot2)
        return result

18. 二叉树的镜像

# -*- coding:utf-8 -*-
'''
题目:操作给定的二叉树,将其变换为源二叉树的镜像。
测试用例:
1)输入为空
2)只有一个根结点,所有结点都没有左子树或右子树
3)普通二叉树
思路:递归,从上至下依次交换左右结点。
'''
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        # write code here
        if root == None:
            return None
        temp = root.left
        root.left = root.right
        root.right = temp
        root.left = self.Mirror(root.left)
        root.right = self.Mirror(root.right)
        return root

19. 顺时针打印矩阵

# -*- coding:utf-8 -*-
'''
题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字.
例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
测试用例:
1)只有一个元素
2)只有一行,一列或者一行一列
3)多行多列
思路:设定代表上下左右四个边界的四个变量,按向右,向下,向左,向下的顺序依次遍历矩阵,每次等于对应坐标的值等于变量值则转向。
'''
class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        # write code here
        up = 0
        down = len(matrix) - 1
        left = 0
        right = len(matrix[0]) - 1
        print_list = []
        while 1:
            if right -left + 1 == 0:
                break
            for j in range(right -left + 1):
                print_list.append((matrix[up][j + left]))
            up += 1
            if down + 1 - up == 0:
                break
            for i in range(down + 1 - up):
                print_list.append(matrix[i + up][right])
            right -= 1
            if right - left + 1 == 0:
                break
            for j in range(right - left + 1):
                print_list.append(matrix[down][right - j])
            down -= 1
            if down + 1 - up == 0:
                break
            for i in range(down + 1 - up):
                print_list.append(matrix[down-i][left])
            left += 1
        return print_list

20.包含min函数的栈

# -*- coding:utf-8 -*-
'''
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
测试用例:
1)新压入栈的数字比之前的最小值大
2)新压入栈的数字比之前的最小值小
3)弹出栈的数字不是最小的元素
4)弹出栈的数字是最小的元素
思路:弄两个栈,一个存所有数据,一个存与所有数据等大小的当前栈的最小数。一起push一起pop。
很多人用了另一个做法。弄两个栈,一个存所有数据,一个只存每次push时新加的最小数据,
然后每次pop时如果两个栈顶相同,则一起pop,否则只pop存所有数据的那个。
这样其实是不对的,想一下如果有好几个相同的最小数,这样就会让存最小数的栈乱套
'''
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self, node):
        # write code here
        self.stack1.append(node)
        if self.top() == []:
            self.stack2.append(node)
        elif node <= self.top():
            self.stack2.append(node)
        else:
            self.stack2.append(self.top())
    def pop(self):
        # write code here
        if self.stack1 != []:
            self.stack1.pop()
            self.stack2.pop()

    def top(self):
        # write code here
        if self.stack2 == []:
            value = []
        else:
            value = self.stack2[-1]
        return value
    def min(self):
        # write code here
        if self.stack2 == []:
            value = []
        else:
            value = self.stack2[-1]
        return value

21. 栈的压入弹出序列

# -*- coding:utf-8 -*-
'''
题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。
例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
测试用例:
1)两个空序列或只有一个数字
2)第二个数组是或者不是第一个数组表示的压入序列对应的栈的弹出序列
思路:使用一个辅助栈。先把压入序列的下一个整数压入辅助栈,如果下一个弹出数字(弹出序列中还存在的第一个)刚好是辅助栈的栈顶,那么辅助栈直接弹出栈顶,弹出序列去掉第一个。
如果下一个弹出的数字不在辅助栈的栈顶,那么把压栈序列中数字依次压入辅助栈,直到下一个需要弹出的数字到达辅助栈的栈顶,此时就可以重复以上操作。
如果剩下的所有压栈序列数字都压入辅助栈了仍然没找到下一个弹出的数字。那么该序列不可能是一个弹出序列。
'''
class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        stack = []
        stack.append(pushV.pop(0))
        # print(stack)
        while 1:
            if pushV == [] and stack == []:
                return 1
            elif pushV == [] and stack[-1] != popV[0]:
                return 0
            if stack[-1] == popV[0]:
                stack.pop()
                popV.pop(0)
            else:
                stack.append(pushV.pop(0))

22.从上往下打印二叉树

# -*- coding:utf-8 -*-
'''
题目:从上往下打印出二叉树的每个节点,同层节点从左至右打印。
测试用例:
1)输入只有根节点,输入为空
2)只有左子树或者只有右子树,左右子树都有的普通子树
思路:每次打印一个结点时,如果它有子节点,把结点放到一个队列的末尾。
接下来到队列头部取出最早进入队列的结点,重复前面的打印操作,直至队列中所有的结点都被打印出来为止。
'''
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        dequeue = []
        final_list = []
        if root == None:
            return []
        dequeue.append(root)
        while dequeue != []:
            root = dequeue[0]
            if root.left != None:
                dequeue.append(root.left)
            if root.right != None:
                dequeue.append(root.right)
            final_list.append((dequeue.pop(0)).val)
        return final_list

23.二叉搜索树的后序遍历序列

# -*- coding:utf-8 -*-
'''
题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
测试用例:
1)输入的后序遍历对应一棵二叉树,包括完全二叉树,所有节点都没有左/右子树的二叉树、只有一个结点的二叉树:输入的后序遍历的序列没有对应一棵二叉树。
2)特殊输入测试(输入数组为None)
思路:最后一个数字是树的根节点的值,数组前面的值可以分为两部分,一部分是左子树结点的值,它们应该都比根节点的值小。第二部分是右子树结点的值,它们应该都比根节点的值大。
然后再用递归的方法分别对两部分进行验证,看它们是否符合二叉搜索树的上述规律。
'''
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if sequence == []:
            return False
        left = []
        right = []
        i = 0
        n = 0
        while i != len(sequence)-1:
            if sequence[i] < sequence[-1] and n == 0:
                left.append(sequence[i])
            elif sequence[i] < sequence[-1] and n == 1:
                return False
            elif sequence[i] > sequence[-1] and n == 0:
                right.append(sequence[i])
                n = 1
            else:
                right.append(sequence[i])
            i += 1
        if left == [] or right == []:
            return True
        self.VerifySquenceOfBST(left)
        self.VerifySquenceOfBST(right)
        return True

24.二叉树中和为某个值的路径

# -*- coding:utf-8 -*-
'''
题目:输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
测试用例:
1)二叉树中没有,有一条,多条符合条件的路径
2)特殊输入测试(输入为None)
思路:
1)递归先序遍历树,把结点加入路径。
2)若该结点是叶子结点则比较当前路径和是否等于期待和。
3)每一轮递归返回到父结点时,当前路径也应该回退一个结点
'''
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def FindPath(self, root, expectNumber):
        # write code here
        if not root:
            return []

        result = []

        def FindPathMain(root, path, currentSum):
            currentSum += root.val

            path.append(root)
            isLeaf = root.left == None and root.right == None

            if currentSum == expectNumber and isLeaf:
                onePath = []
                for node in path:
                    onePath.append(node.val)
                result.append(onePath)

            if currentSum < expectNumber:
                if root.left:
                    FindPathMain(root.left, path, currentSum)
                if root.right:
                    FindPathMain(root.right, path, currentSum)

            path.pop()

        FindPathMain(root, [], 0)

        return result

25.复杂链表的复制

# -*- coding:utf-8 -*-
'''
题目:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),
返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
测试用例:
1)只有一个根节点,random指向自己,两个结点形成环状结构等
2)特殊输入测试(输入为None)
'''
# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
    # 返回 RandomListNode
####错误方法:这样递归会导致只复制对了next,但是random的指针还是指向了原来的链表元素,而不是复制后的新链表####
    # def Clone(self, pHead):
    #     if pHead == None:
    #         return None
    #     clone_head = RandomListNode(pHead.label)
    #     clone_head.next = pHead.next
    #     clone_head.random = pHead.random
    #     clone_head.next = Clone(pHead.next)
    #     return clone_head
#### 正确方法
#### 第一步:根据原始链表的每个结点N创建对应的N',把N'直接链接到N的后面。不包括random
#### 第二步:设置复制出来的结点的random。如果N指向S,那么N'指向S的下一个结点S‘
#### 第三步:把这个长链表分为两个链表,把奇数位置的结点用next连起来就是原始链表,偶数位置用next连起来就是复制出来的链表
    def Clone(self, pHead):
        # write code here
        def copy_label_next(pHead):
            while(pHead != None):
                clone_head = RandomListNode(pHead.label)
                clone_head.next = pHead.next
                pHead.next = clone_head
                pHead = clone_head.next
        def copy_random(pHead):
            while(pHead != None):
                if (pHead.next != None):
                    clone_head = pHead.next
                    if (pHead.random != None):
                        clone_head.random = pHead.random
                    pHead = clone_head.next
        def split_list(pHead):
            clone_head = None
            if (pHead != None):
                clone_head = clone_node = pHead.next
                pHead.next = clone_node.next
                pHead = pHead.next
            while(pHead != None):
                clone_node.next = pHead.next
                clone_node = clone_node.next
                pHead.next = clone_node.next
                pHead = pHead.next
            return clone_head
        copy_label_next(pHead)
        copy_random(pHead)
        return split_list(pHead)

28. 数组中出现次数超过一半的数字

# -*- coding:utf-8 -*-
#题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
class Solution:
    #思路一:可以先用set滤一遍相同元素,再对不同的元素使用count计算出现次数
    def MoreThanHalfNum_Solution(self, numbers):
        numbers_sim = list(set(numbers))
        for number in numbers_sim:
            times = numbers.count(number)
            if times > (len(numbers)/2):
                return (number)
        return 0
    #思路二:次数超过一半的数字也是出现次数最多的数字,我们可以用一次遍历找到出现次数最多的数字,再用一次遍历判定出现次数最多的数字的次数有没有超过总数的一半。
    def MoreThanHalfNum_Solution(self, numbers):
        if numbers == 0:
            return 0
        count = 1
        number = numbers[0]
        for i in numbers[1:]:
            if i == number:
                count += 1
            elif count == 0:
                count = 1
                number = i
            else:
                count -= 1
        count = 0
        for i in numbers:
            if i == number:
                count += 1
        if count * 2 > len(numbers):
            return number
        else:
            return 0

29. 最小的K个数

# -*- coding:utf-8 -*-
#题目:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here
        if k > len(tinput) or k < 1:
            return([])
        print(tinput)
        tinput = sorted(tinput)
        print(tinput)
        output = tinput[0:k]
        return(output)

30. 连续子数组的最大和

# -*- coding:utf-8 -*-
#题目:计算连续子向量的最大和。例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。
class Solution:
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        array_length = len(array)
        array_max = max(array)
        for sub_array_length in range(array_length):
            sub_array_begin = 0
            while (sub_array_begin + sub_array_length) < array_length:
                sub_array_sum = sum(array[sub_array_begin:sub_array_begin + sub_array_length+1]) 
                sub_array_begin += 1
                if array_max < sub_array_sum:
                    array_max = sub_array_sum
        return(array_max)

33. 丑数

# -*- coding:utf-8 -*-
#题目:求按从小到大的顺序的第N个丑数。
#法一思路:首先除2,直到不能整除为止,然后除5到不能整除为止,然后除3直到不能整除为止。最终判断剩余的数字是否为1,如果是1则为丑数,否则不是丑数。这个方法能得到正确结果,但是复杂度过大,在牛客网上会报错运行超时
class Solution:
    def GetUglyNumber_Solution(self, index):
        # write code here
        num = 1
        num_iter = 1
        count = 0
        while 1:
            while num_iter % 2 == 0:
                num_iter = num_iter / 2
            while num_iter % 5 == 0:
                num_iter = num_iter / 5
            while num_iter % 3 == 0:
                    num_iter = num_iter / 3
            if num_iter == 1 :
                count += 1
            if count == index:
                return(num)
            num += 1
            num_iter = num
#法二 由于1是最小的丑数,那么从1开始,把2*1,3*1,5*1,进行比较,得出最小的就是1的下一个丑数,也就是2*1.这个时候,多了一个丑数‘2’,也就又多了3个可以比较的丑数,2*2,3*2,5*2,这个时候就把之前‘1’生成的丑数和‘2’生成的丑数加进来也就是(3*1,5*1,2*2,3*2,5*2)进行比较,找出最小的。。。。如此循环下去就会发现,每次选进来一个丑数,该丑数又会生成3个新的丑数进行比较。
class Solution:
    def GetUglyNumber_Solution(self, index):
        # write code here
        uglynumber_list = [1]
        latest_uglynumber_list = []
        latest_uglynumber = 1
        if index <= 0:
            return(0)
        while len(uglynumber_list) < index:
            latest_uglynumber_list = list(set(latest_uglynumber_list+[latest_uglynumber*2,latest_uglynumber*3,latest_uglynumber*5]))
            latest_uglynumber = min(latest_uglynumber_list)
            uglynumber_list.append(latest_uglynumber)
            latest_uglynumber_list.remove(latest_uglynumber)
        return(uglynumber_list[index-1])
#法三 既然有p<q, 那么2*p<2*q,那么我在前面比你小的数都没被选上,你后面生成新的丑数一定比我大吧,那么你乘2生成的丑数一定比我乘2的大吧,那么在我选上之后你才有机会选上。所以每次我们只用比较3个数:用于乘2的最小的数、用于乘3的最小的数,用于乘5的最小的数。
class Solution:
    def GetUglyNumber_Solution(self, index):
        if (index <= 0):
            return 0
        ugly_list = [1]
        index_2 = 0
        index_3 = 0
        index_5 = 0
        for i in range(index-1):
            new_ugly = min(ugly_list[index_2]*2, ugly_list[index_3]*3, ugly_list[index_5]*5)
            ugly_list.append(new_ugly)
            if (new_ugly % 2 == 0):
                index_2 += 1
            if (new_ugly % 3 == 0):
                index_3 += 1
            if (new_ugly % 5 == 0):
                index_5 += 1
        return ugly_list[-1]

34. 第一个只出现一次的字符

# -*- coding:utf-8 -*-
#题目:在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置
#思路:先用set把重复的字滤掉,需要注意的是set之后列表的顺序就打乱了,需要再用sort把列表顺序还原一下.然后照着列表里的字符顺序去统计字符出现次数,找到第一个出现一次的,返回.
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        if s == "":
            return(-1)
        no_repeat_s = list(set(s))
        no_repeat_s.sort(key = s.index)
        for i in no_repeat_s:
            times = s.count(i)
            if times == 1:
                return(s.find(i))

40. 数组中只出现一次的数字

# -*- coding:utf-8 -*-
#题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
        # write code here
        array_simple = list(set(array))
        array_simple.sort(key = array.index)
        two_numbers = []
        for i in array_simple:
            if (array.count(i) == 1):
                two_numbers.append(i)
                if len(two_numbers) == 2:
                    return(two_numbers)

41. 和为s的连续正数序列

# -*- coding:utf-8 -*-
#题目:在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置
#思路:先用set把重复的字滤掉,需要注意的是set之后列表的顺序就打乱了,需要再用sort把列表顺序还原一下.然后照着列表里的字符顺序去统计字符出现次数,找到第一个出现一次的,返回.
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        if s == "":
            return(-1)
        no_repeat_s = list(set(s))
        no_repeat_s.sort(key = s.index)
        for i in no_repeat_s:
            times = s.count(i)
            if times == 1:
                return(s.find(i))

47.求1+2+3+…+n

# -*- coding:utf-8 -*-
#题目:求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
class Solution:
    def Sum_Solution(self, n):
        # write code here
        return n and (n + self.Sum_Solution(n-1))

65.矩阵中的路径

# -*- coding:utf-8 -*-
'''
题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。
如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。
例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,
但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
测试用例:
1)特殊输入测试,输入为空
2)边界值测试(矩阵只有一行或一列,矩阵和路径中所有的字母都相同)
3)功能测试(在多行多列的矩阵中存在或不存在路径)
思路:首先选择一个格子作为起点,如果和路径起点相同,那么就搜索它的上下左右去寻找路径的下一个点。如果找到了下一个点就继续搜索上下左右搜索下下一个点
要是没有找到下一个点或下下一个点,那说明此路不通,返回到当前点的上一个点,重新去找。因为路径不能重复进入矩阵的格子,做一个mask矩阵,用过的点都做个标记。
一直重复这个过程直到在矩阵中找到路径字符串,或者已经试过所有组合可能。
'''
class Solution:
    def hasPathCore(self, matrix, rows, cols, row, col, path_index, path):
        if path_index == len(path):
            return True
        if (row in range(rows) and col in range(cols) and matrix[row * cols + col] == path[path_index] and not self.visited[
            row * cols + col]):
            path_index += 1
            self.visited[row * cols + col] = 1
            result = (self.hasPathCore(matrix, rows, cols, row, col - 1, path_index, path) or
                      self.hasPathCore(matrix, rows, cols, row - 1, col, path_index, path) or
                      self.hasPathCore(matrix, rows, cols, row + 1, col, path_index, path) or
                      self.hasPathCore(matrix, rows, cols, row, col + 1, path_index, path))
            if (not result):
                path_index -= 1
                self.visited[row * cols + col] = 0
            return result
    def hasPath(self, matrix, rows, cols, path):
        # write code here
        if (matrix == None or rows < 1 or cols < 1 or path == None):
            return False

        self.visited = [0]*len(matrix)

        path_index = 0
        for row in range(rows):
            for col in range(cols):
                if self.hasPathCore(matrix,rows,cols,row,col,path_index,path):
                    return True
        return False

66.机器人的运动范围

# -*- coding:utf-8 -*-
'''
题目:地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,
每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。
例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。
但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
测试用例:
1)功能测试(方格为多行多列:k为正数)
2)边界值测试(方格只有一行或者只有一列:k等于0)
3)特殊输入测试(k为负数)
思路:类似矩阵中的路径那个题。
'''
class Solution:
    def movingCount(self, threshold, rows, cols):
        if (threshold < 0 or rows < 0 or cols < 0):
            return 0
        self.mask = [0] * rows * cols
        self.sum = 0
        row = 0
        col = 0
        self.movingCountCore(threshold, rows, cols, row, col, self.mask)
        return self.sum

    def movingCountCore(self,threshold, rows, cols, row, col,mask):
        count = self.getDigitSum(row) + self.getDigitSum(col)
        if -1 < row < rows and -1 < col < cols and count <= threshold and self.mask[row * cols + col] == 0 :
            self.mask[row * cols + col] = 1
            self.sum += 1
            self.movingCountCore(threshold, rows, cols, row - 1, col, self.mask)
            self.movingCountCore(threshold, rows, cols, row + 1, col, self.mask)
            self.movingCountCore(threshold, rows, cols, row, col - 1, self.mask)
            self.movingCountCore(threshold, rows, cols, row, col + 1, self.mask)

    def getDigitSum(self, number):
        sum = 0
        while(number > 0):
            sum += number % 10
            number //= 10
        return sum