剑指offer刷题

1、二维数组中查找

题目描述:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

思路:可以利用从左到右递增、从上到下递增的特点,开始从数组最右上角开始查找。如果array[rows][cols]比该整数小则row++,如果比该整数大则col--,找到返回True,如果直到数组越界了还没有找到的话就返回False。

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        rows= len(array) - 1
        row = 0
        col = len(array[0]) - 1
        flag = False
        while row <= rows and col >= 0:
        	if array[row][col] == target:
        		flag = True
        		break
        	elif array[row][col] > target:
        		col -= 1
        	else:
        		row += 1
        return flag

2、替换空格

题目描述:请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

思路:C语言可以先统计空格个数m,然后new一个新指针指向一个大小为3*m+n长度新的内存空间,遍历原字符串复制字符到新字符串中,遇到空格则加‘%’,‘2’,‘0’三个字符。我直接用了python字符串的替换函数,哈哈哈哈哈哈

# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        newStr = s.replace(' ', '%20')
        return newStr

3、从尾到头打印链表

题目描述:输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

思路:1、利用头插法,新建一个链表,将原链表数据按照头插法的思路插入到新链表。

            2、利用栈的特点,递归。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        
        pTemp = listNode
        p = []
        while pTemp != None:
            p.insert(0, pTemp.val)
            pTemp = pTemp.next
        return p
        
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        
        ret = []
        def reverse(Node):
            if Node:
                reverse(Node.next)
                ret.append(Node.val)
        reverse(listNode)
        return ret
   

4、重建二叉树

题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

思路:前序遍历的第一个数是树的根节点,根据树的根节点在可以在中序遍历中将树的左右子树分离出来。左右子树的前序中序遍历也可根据上述思路分离出来,有终止条件,这就可以用递归来做了。

# -*- 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)==0:
            return None
        if len(pre)==1:
            return TreeNode(pre[0])
        root = TreeNode(pre[0])
        root_left = tin[:tin.index(pre[0])]
        root_right = tin[tin.index(pre[0])+1:]
        root.left = self.reConstructBinaryTree(pre[1:tin.index(pre[0])+1], root_left)
        root.right = self.reConstructBinaryTree(pre[tin.index(pre[0])+1:], root_right)
        return root

5、用两个栈实现队列

题目描述:用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

思路:队列先入先出,定义两个栈Push栈和Pop栈。当执行Push操作时,就直接往Push栈里append数据。但执行Pop操作时,先判断Pop栈是否为空,如果不为空直接放回最后一个元素,否则判断Push栈是否为空,不为空的话把Push栈里的数据全部append到Pop栈里面,最后输出Pop栈的最后一个元素。

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self, node):
        self.stack1.append(node)
        # write code here
    def pop(self):
        # return xx
        if self.stack2 == []:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        return self.stack2.pop()

6、旋转数组的最小数字

题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

思路:最暴力的解法就是遍历数组找到数组最小的元素,时间复杂度为O(n)。这里我使用二分法的思想,最小的元素应该满足比它的前后元素都小。

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
 
        if len(rotateArray) == 0:
            return 0
        left = 0
        right = len(rotateArray) - 1
        while left < right:
            if rotateArray[left] < rotateArray[right]:
                return rotateArray[left]
            mid = left + (right - left) // 2
            if rotateArray[left] < rotateArray[mid]:
                left = mid + 1
            elif rotateArray[mid] < rotateArray[right]:
                right = mid
            else:
                left += 1
        return rotateArray[left]

7、斐波那契数列

题目描述:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。 

n<=39

思路:通式为a(n) = a(n - 1) + a(n - 2)  n>=2, 可以用for循环也可以递归

# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        # write code here
        if n <= 1:
            return n
        else:
            i = 2
            first = 0
            second = 1
            while i <=n:
                result = first + second
                first = second
                second = result
                i = i + 1
            return result
                

8、跳台阶

题目描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

思路:通式为a(n) = a(n - 1) + a(n - 2), n>=2 其中a(1) = 1, a(2) = 2。

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloor(self, number):
        # write code here
        if number == 0:
            return 0
        if number == 1:
            return 1
        if number == 2:
            return 2
        exp_1 = 1
        exp_2 = 2
        for i in range(2, number):
            result = exp_1 + exp_2
            exp_1 = exp_2
            exp_2 = result
        return result

9、变态跳台阶

题目描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

思路:通式为a(n) = 2 * a(n - 1), 推导过程为a(n) = a(1) + a(2) + ..... + a(n - 1) (1) , a(n - 1) = a(1) + a(2) + ..... + a(n - 2)(2), 则(2)代入(1)可得。

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # write code here
        if number == 0:
            return 0
        if number == 1:
            return 1
        if number == 2:
            return 2
        exp_1 = 1
        exp_2 = 2
        for i in range(2, number):
            result = 2 * exp_2
            exp_2 = result
        return result
        

10、矩形覆盖

题目描述:

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 

比如n=3时,2*3的矩形块有3种覆盖方法:

思路:通式为a(n) = a(n - 1) + a(n - 2), a(n - 1)为矩形竖着覆盖的情况, a(n - 2)为横着覆盖。

# -*- coding:utf-8 -*-
class Solution:
    def rectCover(self, number):
        # write code here
        # f(n) = f(n - 1) + f(n - 2)

        if number <= 2:
            return number
        a = 1
        b = 2
        for i in range(2, number):
            result = a + b 
            a = b 
            b = result
        return result

11、二进制中1的个数

题目描述:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

思路:正整数的补码是其二进制表示,与原码相同。负整数的补码,将其原码除符号位外的所有位取反(0变1,1变0,符号位为1不变)后加1。第一个思路可以将整数分别与32位中的每一位做与操作,如果不为0,个数加一。第二个思路如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
       # first solution
        count = 0
        for i in range(32):
            mask = 1 << i
            if n & mask != 0:
                count += 1
        return count
        
        '''
        # second solution
        count = 0
        while n != 0:
            count = count + 1
            n = n&(n - 1)
        return count
        '''

12、数值的整数次方

题目描述:

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 保证base和exponent不同时为0

思路:分exponent>0, exponent<0两种情况来做就行了。第二种情况用快速幂来做,也就是位运算

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        if base == 0:
            return 0
        if exponent == 0:
            return 1
        flag = False
        if exponent < 0:
            flag = True
            exponent = -exponent
        Ret = 0
        for i in range(exponent):
            if Ret == 0:
                Ret = base
            else:
                Ret *= base
        if flag:
            return 1.0 / Ret
        else:
            return Ret
# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
  
        if base == 0:
            return 0
        if exponent == 0:
            return 1
        flag = False
        ans = 1
        if exponent < 0:
            flag = True
            exponent = -exponent
        while exponent > 0:
            if exponent & 1 == 1:
                ans *= base
            exponent >>= 1
            base *= base
        return 1.0 / ans if flag else ans

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

题目描述:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

思路:第一种可以用两个list分别保存数组种的奇数和偶数,然后将两个list合并就好了。第二张可以借用冒泡排序的思想。

# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        # write code here
        # first solution
        '''
        if array == None:
            return []
        if len(array) == 1:
            return array
        oddArray = []
        evenArray = []
        for i in array:
            if i % 2 != 0:
                oddArray.append(i)
            else:
                evenArray.append(i)
        oddArray.extend(evenArray)
        return oddArray
        '''

        # second solution
        num = len(array)
        if num <= 1:
            return array
        for i in range(num):
            for j in range(num - 1):
                if array[j] % 2 == 0 and array[j + 1] % 2 == 1:
                    array[j], array[j+1] = array[j+1], array[j]
        return array
        

14、链表中倒数第K个节点

问题描述:输入一个链表,输出该链表中倒数第k个结点。

思路:首先两个指针都指向头节点,然后第一个指针走k步,接下来一起走。第一个指针走到尾端的时候,输出第二个指针指向的节点。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        secondNode = head
        firstNode = head
        for i in range(k):
            if firstNode == None:
                return None
            firstNode = firstNode.next
        while firstNode:
            firstNode = firstNode.next
            secondNode = secondNode.next
        return secondNode

15、反转链表

问题描述:输入一个链表,反转链表后,输出新链表的表头。

思路:用三个指针,迭代法。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if pHead == None:
            return None
        if pHead.next == None:
            return pHead
        first = pHead
        second = pHead.next
        third = second.next
        first.next = None
        while third != None:
            second.next = first
            first = second
            second = third
            third = third.next
        second.next = first
        return second

16、合并两个排序的链表

题目描述:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

思路:正常推理即可。

# -*- coding:utf-8 -*-
# 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
        newHead = pHead1 if pHead1.val < pHead2.val else pHead2
        tHead1 = pHead1
        tHead2 = pHead2
        tHead = newHead
        if newHead == tHead1:
            tHead1 = tHead1.next
        else:
            tHead2 = tHead2.next
        while tHead1 and tHead2:
            if tHead1.val < tHead2.val:
                tHead.next = tHead1
                tHead = tHead1
                tHead1 = tHead1.next
            else:
                tHead.next = tHead2
                tHead = tHead2
                tHead2 = tHead2.next
        if tHead1 != None:
            tHead.next = tHead1
        else:
            tHead.next = tHead2
        return newHead

17、树的子结构

题目描述:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路:子树的意思是包含了一个结点,就得包含这个结点下的所有节点,一棵大小为n的二叉树有n个子树,就是分别以每个结点为根的子树。子结构的意思是包含了一个结点,可以只取左子树或者右子树,或者都不取。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        if pRoot1 == None or pRoot2 == None:
            return False
        
        def judgeSubTree(pRoot1, pRoot2):
            if pRoot2 == None:
                return True
            if pRoot1 == None:
                return False
            if pRoot1.val == pRoot2.val:
                if pRoot2.left == None:
                    leftEqual = True
                else:
                    leftEqual = judgeSubTree(pRoot1.left, pRoot2.left)
                if pRoot2.right == None:
                    rightEqual = True
                else:
                    rightEqual = judgeSubTree(pRoot1.right, pRoot2.right)
                return leftEqual and rightEqual
            return False
        if pRoot1.val == pRoot2.val:
            ret = judgeSubTree(pRoot1, pRoot2)
            if ret:
                return True
        leftRet = self.HasSubtree(pRoot1.left, pRoot2)
        
        rightRet = self.HasSubtree(pRoot1.right, pRoot2)
        
        return leftRet or rightRet
        
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(root1==null||root2==null) return false;
        boolean result=false;
        if(root1.val==root2.val){
            result = HasSubtreeHelper(root1,root2);
        }
        if(!result) result = HasSubtree(root1.left,root2);
        if(!result) result = HasSubtree(root1.right,root2);
        return result;
    }
 
    public boolean HasSubtreeHelper(TreeNode r1,TreeNode r2){
        if(r2==null) return true;
        if(r1==null) return false;
        if(r1.val!=r2.val) return false;
        return HasSubtreeHelper(r1.left,r2.left)&&HasSubtreeHelper(r1.right,r2.right);
    }

18、二叉树的镜像

题目描述:操作给定的二叉树,将其变换为源二叉树的镜像。

思路:递归交换位置即可。

# -*- 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
        root.left, root.right = root.right, root.left
        
        self.Mirror(root.left)
        self.Mirror(root.right)
        # 非递归,层次遍历
        '''
        if root == None:
            return None
        ret = [root]
        while ret:
        	temp = ret[0]
        	if temp.right:
        		ret.append(temp.right)
        	if temp.left:
        		ret.append(temp.left)
        	temp.left, temp.right = temp.right, temp.left
        	del ret[0]
        return root
        '''

19、顺时针打印矩阵

题目描述:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 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。

思路:定义四个变量代表范围,top、bottom、left、right

  1. 向右走存入整行的值,当存入后,该行再也不会被遍历,代表上边界的 top 加一,同时判断是否和代表下边界的 bottom 交错 
  2. 向下走存入整列的值,当存入后,该列再也不会被遍历,代表右边界的 right 减一,同时判断是否和代表左边界的 left 交错 
  3. 向左走存入整行的值,当存入后,该行再也不会被遍历,代表下边界的 bottom 减一,同时判断是否和代表上边界的 top 交错 
  4. 向上走存入整列的值,当存入后,该列再也不会被遍历,代表左边界的 left 加一,同时判断是否和代表右边界的 right 交错
# -*- coding:utf-8 -*-
class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):

        # write code here
        '''
        row = len(matrix)
        col = len(matrix[0])
        l = []
        start = 0
        while row > 2*start and col > 2*start:
            endx = row - 1 - start
            endy = col - 1 - start
            for i in range(start, endy+1):
                l.append(matrix[start][i])
            if start < endx:
                for i in range(start+1, endx+1):#角上的重复算了一次
                    l.append(matrix[i][endy])
            if start < endx and start < endy:
                for i in range(endy-1, start-1, -1):
                    l.append(matrix[endx][i])
            if start < endx-1 and start < endy:
                for i in range(endx-1, start, -1):
                    l.append(matrix[i][start])
            start += 1
        return l
        '''
    	ret = []
    	top = 0
    	bottom = len(matrix) - 1
    	left = 0
    	right = len(matrix[0]) - 1
    	while True:
    		for i in range(left, right + 1):
    			ret.append(matrix[top][i])
    		top += 1
    		if top > bottom:
    			break
    		for i in range(top, bottom + 1):
    			ret.append(matrix[i][right])
    		right -= 1
    		if right < left:
    			break
    		for i in range(right, left - 1, -1):
    			ret.append(matrix[bottom][i])
    		bottom -= 1
    		if bottom < top:
    			break
    		for i in range(bottom, top - 1, -1):
    			ret.append(matrix[i][left])
    		left += 1
    		if left > right:
    			break
    	return ret

        # write code here
        '''
        rows=len(matrix)
        cols=len(matrix[0])
        result=[]
        if rows==0 and cols==0:
            return result
        left,right,top,bottom = 0,cols-1,0,rows-1
        
        while left<=right and top<=bottom:
            for i in range(left,right+1):
                result.append(matrix[top][i])
            for i in range(top+1,bottom+1):
                result.append(matrix[i][right])
            if top!=bottom:
                for i in range(right-1,left-1,-1):
                    result.append(matrix[bottom][i])
            if left!=right:
                for i in range(bottom-1,top,-1):
                    result.append(matrix[i][left])
            left+=1
            right-=1
            top+=1
            bottom-=1
        return result
        '''

20、包含min函数的栈

问题描述:

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)。注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。

思路:使用一个辅助最小栈来保留当前长度栈中的最小值。

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack = []
        self.minValue = []
        
    def push(self, node):
        # write code here
        self.stack.append(node)
        if self.minValue:
            if self.minValue[-1] > node:
                self.minValue.append(node)
            else:
                self.minValue.append(self.minValue[-1])
        else:
            self.minValue.append(node)
    def pop(self):
        # write code here
        if self.stack == []:
            return None
        self.minValue.pop()
        return self.stack.pop()
    def top(self):
        # write code here
        if self.stack == []:
            return None
        return self.stack[-1]
    def min(self):
        # write code here
        if self.minValue == []:
            return None
        return self.minValue[-1]

21、栈的压入、弹出序列

题目描述:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

思路:使用一个辅助列表,将压入顺序的序列依次压入辅助列表中,当压入的序列和弹出序列开始的数字相同时,辅助列表弹出这个数,弹出序列也往后走一位。最后判断是否为弹出序列是看辅助列表是否为空,为空则是,不为空则不是。

# -*- coding:utf-8 -*-
class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        if pushV and len(pushV) != len(popV):
            return None
        stack = []
        index = 0
        for item in pushV:
            stack.append(item)
            while stack and stack[-1] == popV[index]:
                stack.pop()
                index += 1
        if stack == []:
            return True
        else:
            return False

22、从上往下打印二叉树

题目描述:从上往下打印出二叉树的每个节点,同层节点从左至右打印。

思路:树的层次遍历。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        # write code here
        if root == None:
            return []
        tempList = [root]
        ret = []
        while tempList:
            temp = tempList[0]
            ret.append(temp.val)
            if temp.left:
                tempList.append(temp.left)
            if temp.right:
                tempList.append(temp.right)
            del tempList[0]
        return ret

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

题目描述:输入一个非空整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

思路:二叉搜索树:它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值。若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。利用二叉搜索树根节点比左子树节点值大比右子树节点值小,后序遍历最后一个为根节点的特点来做。

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if sequence == []:
            return False
        seqLen = len(sequence) - 1
        count = 0
        while seqLen:
            while sequence[count] < sequence[seqLen]:
                count += 1
            while sequence[count] > sequence[seqLen]:
                count += 1
            if count < seqLen:
                return False
            count = 0
            seqLen -= 1
        return True
        '''
        if sequence == []:
            return False
        val = sequence[-1]
        index = None
        for i in range(len(sequence) - 1):
            if index == None and sequence[i] > val:
                index = i
            if index != None and sequence[i] < val:
                return False
        
        leftRet = True
        rightRet = True
        if index > 0:
            leftRet = self.VerifySquenceOfBST(sequence[:index])
        if index > len(sequence) - 1:
            rightRet = self.VerifySquenceOfBST(sequence[index:len(sequence) - 1])
        return leftRet and rightRet
        '''
        '''
        if not sequence:
            return False
        #找到根节点
        root = sequence[-1]
        i = 0
        #找到左子树和右子树的分界点
        while i < len(sequence) - 1:
            if sequence[i] > root:
                break
            i += 1
        for j in range(i,len(sequence)-1):
            if sequence[j] < root:
                return False
        left = True
        right = True
        if i > 0:
            left = self.VerifySquenceOfBST(sequence[:i])
        if i < len(sequence) - 1:
            right = self.VerifySquenceOfBST(sequence[i:len(sequence) - 1])
        return left and right
        '''

24、二叉树中和为某一值的路径

题目描述:输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

思路:深度优先遍历,保存所有到根节点的路径。输出满足要求的路径。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
import copy
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def FindPath(self, root, expectNumber):
        # write code here
        if root == None:
            return []
        ret = []
        supportArrayList = [[root.val]]
        support = [root]
        while support:
            tempNode = support[0]
            tempArrayList = supportArrayList[0]
            if tempNode.left == None and tempNode.right == None:
                if sum(tempArrayList) == expectNumber:
                    ret.insert(0, tempArrayList)
            if tempNode.left:
                newArrayList = copy.copy(tempArrayList)
                newArrayList.append(tempNode.left.val)
                support.append(tempNode.left)
                supportArrayList.append(newArrayList)
            if tempNode.right:
                newArrayList = copy.copy(tempArrayList)
                newArrayList.append(tempNode.right.val)
                support.append(tempNode.right)
                supportArrayList.append(newArrayList)
            del support[0]
            del supportArrayList[0]
        return ret

25、复杂链表的复制

题目描述:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

思路:python中的copy模块有个deepcopy函数,可以直接AC 哈哈哈哈哈哈哈。我这思路是先将链表复制,然后根据原链表的next指针和random指针来指新链表的指针,最后将原链表断开。

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
import copy
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        # write code here
        # 复制每个节点,如复制A节点A1,将A1插到A的后面
        if pHead is None:
            return None
        copyNode = pHead
        while copyNode:
        	tempNode = RandomListNode(copyNode.label)
        	nextNode = copyNode.next
        	copyNode.next = tempNode
        	tempNode.next = nextNode
        	copyNode = nextNode
        # 重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next
        copyNode = pHead
        while copyNode:
        	copyNode.next.random = None if copyNode.random == None else copyNode.random.next
        	copyNode = copyNode.next.next
        # 拆分链表,将链表拆分为原链表和复制后的链表
        cloneHead = pHead.next
        copyNode = pHead
        n = pHead
        while copyNode:
        	tempNode = copyNode.next
        	copyNode.next = tempNode.next
        	tempNode.next = None if tempNode.next == None else tempNode.next.next
        	copyNode = copyNode.next
        return cloneHead

26、二叉搜索树与双向链表***

题目描述:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

思路:首先要找到双向链表头节点,如果二叉搜索树有左子树的话,那么它的最左的叶子节点就是头节点。如果只有右子树的话,那么二叉搜索树的根节点就是双向链表的头节点。也可以使用中序递归遍历存入列表,最后将列表中的节点中指针进行调换,返回list1[0]。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Convert(self, pRootOfTree):
        # write code here
        if pRootOfTree == None:
            return None
        def findLeftRight(left):
            while left.right:
                left = left.right
            return left
        
        leftNode = self.Convert(pRootOfTree.left)
        rightNode = self.Convert(pRootOfTree.right)
        retNode = leftNode
        if leftNode:
            leftNode = findLeftRight(leftNode)
        else:
            retNode = pRootOfTree
        pRootOfTree.left = leftNode
        pRootOfTree.right = rightNode
        if leftNode != None:
            leftNode.right = pRootOfTree
        if rightNode != None:
            rightNode.left = pRootOfTree
        return retNode
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def zhongxu(self,root):
        if not root:
            return []
        return self.zhongxu(root.left)+[root]+self.zhongxu(root.right)
    def Convert(self, pRootOfTree):
        # write code here
        list1=self.zhongxu(pRootOfTree)
        if len(list1)==0:
            return None
        if len(list1)==1:
            return pRootOfTree
        for i in range(len(list1)-1):
            list1[i].right=list1[i+1]
            list1[i+1].left=list1[i]
        return list1[0]

27、字符串的排列***

题目描述:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

思路:递归打印就好了

# -*- coding:utf-8 -*-
class Solution:
    def Permutation(self, ss):
        # write code here
        l = []
        if len(ss) <= 1:
            return ss
        n = len(ss)
        i = 0
        while i < n:
            #temp = ss[i] + self.Permutation(ss[:i]+ss[i+1:])
            for j in self.Permutation(ss[:i]+ss[i+1:]):
                temp = ss[i] + str(j)
                if temp not in l:
                    l.append(temp)
            i += 1
        return l

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

题目描述:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

思路: 两两不相同的数字相互抵消,剩下了的数字嘉定是超过一半的次数的数字,最后遍历一遍数组验证一下就可以了

# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        ''' First Solution
        tempDict = {}
        numLen = len(numbers)
        for num in numbers:
            if num in tempDict:
                tempDict[num] += 1
            else:
                tempDict[num] = 1
            if tempDict[num] > (numLen >> 1):
                return num
        return 0
        '''    
        first = 0
        preCount = 0
        numLen = len(numbers)
        for num in numbers:
            if preCount == 0:
                first = num
                preCount += 1
            else:
                if first == num:
                    preCount += 1
                else:
                    preCount -= 1
        if preCount == 0:
            return 0
        else:
            Count = 0
            for num in numbers:
                if num == first:
                    Count += 1
            if Count > (numLen >> 1):
                return first
            return 0

29、最小K个数***

题目描述:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

思路:用大根堆这个数据结构。

# -*- coding:utf-8 -*-
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here

        def createMaxHeap(num):
            maxHeap.append(num)
            currentIndex = len(maxHeap) - 1
            while currentIndex != 0:
                parentIndex = (currentIndex - 1) >> 1
                if maxHeap[parentIndex] < maxHeap[currentIndex]:
                    maxHeap[parentIndex], maxHeap[currentIndex] = maxHeap[currentIndex], maxHeap[parentIndex]
                    currentIndex = parentIndex
                else:
                    break
        
        def adjustMaxHeap(num):
            if num < maxHeap[0]:
                maxHeap[0] = num
            maxHeapLen = len(maxHeap)
            index = 0
            while index < maxHeapLen:
                leftIndex = index * 2 + 1
                rightIndex = index * 2 + 2
                largeIndex = 0
                if rightIndex < maxHeapLen:
                    if maxHeap[rightIndex] < maxHeap[leftIndex]:
                        largeIndex = leftIndex
                    else:
                        largeIndex = rightIndex
                elif leftIndex < maxHeapLen:
                    largeIndex = leftIndex
                else:
                    break
                if maxHeap[index] < maxHeap[largeIndex]:
                    maxHeap[index], maxHeap[largeIndex] = maxHeap[largeIndex], maxHeap[index]
                index = largeIndex
                
        maxHeap = []
        inputLen = len(tinput)
        if inputLen < k or k <= 0:
            return []
        for i in range(inputLen):
            if i < k:
                createMaxHeap(tinput[i])
            else:
                adjustMaxHeap(tinput[i])
        maxHeap.sort()
        return maxHeap
        

30、连续子数组的最大和

问题描述:HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

思路:动态规划问题,如果array[0] + .....+ array[n] >= array[n]则可以继续加下去,不然直接从array[n]从头开始加

# -*- coding:utf-8 -*-
class Solution:
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        maxSum = None
        tempNum = 0
        for i in array:
            if maxSum == None:
                maxSum = i
            if tempNum + i < i:
                tempNum = i
            else:
                tempNum += i
            if tempNum > maxSum:
                maxSum = tempNum
        return maxSum

31、整数中出现1的次数***

题目描述:求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

思路:设定整数点(如1、10、100等等)作为位置点i(对应n的各位、十位、百位等等),分别对每个数位上有多少包含1的点进行分析。根据设定的整数位置,对n进行分割,分为两部分,高位n/i,低位n%i 。

当i表示百位,且百位对应的数>=2,如n=31456,i=100,则a=314,b=56,此时百位为1的次数有a/10+1=32(最高两位0~31),每一次都包含100个连续的点,即共有(a%10+1)*100个点的百位为1 。

当i表示百位,且百位对应的数为1,如n=31156,i=100,则a=311,b=56,此时百位对应的就是1,则共有a%10(最高两位0-30)次是包含100个连续点,当最高两位为31(即a=311),本次只对应局部点00~56,共b+1次,所有点加起来共有(a%10*100)+(b+1),这些点百位对应为1 。

当i表示百位,且百位对应的数为0,如n=31056,i=100,则a=310,b=56,此时百位为1的次数有a/10=31(最高两位0~30) 

综合以上三种情况,当百位对应0或>=2时,有(a+8)/10次包含所有100个点,还有当百位为1(a%10==1),需要增加局部点b+1 。之所以补8,是因为当百位为0,则a/10==(a+8)/10,当百位>=2,补8会产生进位位,效果等同于(a/10+1)

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        '''
        index = 1
        count = 0
        sumNum = 0
        highNum = 1
        midNum = 1
        lowNum = 1
        while highNum != 0:
            highNum = n // (index * 10)
            midNum = (n // index) % 10
            lowNum = n % index
            index = index * 10
            if midNum == 0:
                num = highNum * pow(10, count)
            elif midNum > 1:
                num = (highNum + 1) * pow(10, count)
            else:
                num = highNum * pow(10, count) + lowNum + 1
            sumNum += num
            count += 1
        return sumNum
        '''
        count = 0
        i = 1
        while i <= n:
            first = n / i
            second = n % i
            count += (first + 8) / 10 * i + (first % 10 == 1)*(second + 1)
            i *= 10
        return count

32、把数组排成最小的数

题目描述:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

思路:我这里用的是冒泡排序的思想,两两数字拼接,如果前面的拼成的数字比后面拼成的数字要大,则两两互换位置。简单意思就是局部最小促成全局最小。

# -*- coding:utf-8 -*-
class Solution:
    def PrintMinNumber(self, numbers):
        # write code here
        Len = len(numbers)
        for i in range(Len):
            for j in range(i + 1, Len):
                if int((str(numbers[j])+str(numbers[i])) < (str(numbers[i])+str(numbers[j]))):
                    numbers[j], numbers[i] = numbers[i], numbers[j]
        return ''.join([str(num) for num in numbers])

33、丑数

题目描述:把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

思路:所有的丑数都是2, 3 ,5这三个数的乘积所得来的。定义一个丑数列表,三个指针分别代表2, 3, 5三个数在丑数列表最小值所在的下标,每次三个指针都乘上2, 3, 5三个数,最小的数放入丑数列表中,然后当前指针指向的下标加一。最后的终止条件是丑数列表大小为N。

# -*- coding:utf-8 -*-
class Solution:
    def GetUglyNumber_Solution(self, index):
        # write code here
        if index < 1:
            return 0
        uglyList = [1]
        twoPointer = 0
        threePointer = 0
        fivePointer = 0
        for i in range(index - 1):
            uglyValue = min(2*uglyList[twoPointer], 3*uglyList[threePointer], 5*uglyList[fivePointer])
            uglyList.append(uglyValue)
            if uglyValue == uglyList[twoPointer]*2:
                twoPointer += 1
            if uglyValue == uglyList[threePointer]*3:
                threePointer += 1
            if uglyValue == uglyList[fivePointer]*5:
                fivePointer += 1
        return uglyList[-1]

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

题目描述:在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)

思路:最简单粗暴的方法就是遍历一遍字符串,用count函数看字符出现的次数是否为1。

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        
        if not s:
            return -1
        for i in range(len(s)):
            if s.count(s[i]) == 1:
                return i
        return -1

35、数组中的逆序对***

题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

思路:归并排序在合并的时候统计逆序对。

# -*- coding:utf-8 -*-
count = 0
class Solution:
    def InversePairs(self, data):
        # write code here
        '''
        # only pass 50% data
        arrLen = len(data)
        count = 0
        for i in range(1, arrLen):
        	for j in range(i):
        		if data[j] > data[i]:
        			count += 1
        return count % 1000000007
        '''
        
        global count
        def MergeSort(lists):
            global count
            if len(lists) <= 1:
                return lists
            num = int( len(lists)/2 )
            left = MergeSort(lists[:num])
            right = MergeSort(lists[num:])
            r, l=0, 0
            result=[]
            while l

36、两个链表的第一个公共节点

题目描述:输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

思路:第一种思路是计算长链表和短链表相差的长度k,然后先长链表走k步,再长短链表一起走,最后两个链表走到的节点相同时就是第一个公共节点。第二种思路是把两个链表的值分别存在存在两个列表里面,因为公共节点后两个链表的节点是相同的,我们可以把两个列表的节点pop出来,如果两个节点的值不相同的话,那么他们的下一个节点就是第一个公共节点。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        '''
        def findNode(longTemp, shortHead, longHead):
            k = 0
            while longTemp:
                longTemp = longTemp.next
                k += 1
            shortTemp = shortHead
            longTemp = longHead
            for i in range(k):
                longTemp = longTemp.next
            while shortTemp != longTemp:
                shortTemp = shortTemp.next
                longTemp = longTemp.next
            return shortTemp
        pTemp1 = pHead1
        pTemp2 = pHead2
        while pTemp1 and pTemp2:
            if pTemp1 == pTemp2:
                return pTemp2
            pTemp1 = pTemp1.next
            pTemp2 = pTemp2.next
        if pTemp1:
            return findNode(pTemp1, pHead2, pHead1)
        if pTemp2:
            return findNode(pTemp2, pHead1, pHead2)
        '''

        listA, listB = [], []
        if not pHead2 and not pHead1:
            return None
        while pHead1:
            listA.append(pHead1)
            pHead1 = pHead1.next
        while pHead2:
            listB.append(pHead2)
            pHead2 = pHead2.next
        length = min(len(listB), len(listA))
        temp=None
        for i in range(length):
            nodeA = listA.pop()
            nodeB = listB.pop()
            if nodeA == nodeB:
                temp = nodeA
            else:
                break
        return temp

37、数字在排序数组中出现的次数

题目描述:统计一个数字在排序数组中出现的次数。

思路:这个数组要是有序数组,才能用二分法来做。利用二分法,寻找第一个和最后一个出现的k。

# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        if not data :
            return 0
        def getfirst(data,k):
            length = len(data)
            index1 = 0
            index2 = length - 1
            while index1 <= index2:
                mid = (index2 - index1) // 2 + index1
                if data[mid] == k :
                     if (mid > index1 and data[mid - 1] != k) or mid == index1:
                        return mid
                     else:
                        index2 = mid - 1
                elif data[mid] > k:
                     index2 = mid - 1
                else:
                     index1 = mid + 1
            return -1 

        def getend(data,k):
            length = len(data)
            index1 = 0
            index2 = length - 1
            while index1 <= index2:
                mid = (index2 - index1) // 2 + index1
                if data[mid] == k :
                    if (mid < index2 and data[mid + 1] != k) or mid == index2:
                        return mid
                    else :
                        index1 = mid + 1
                elif data[mid] > k:
                    index2 = mid - 1
                else:
                    index1 = mid + 1
            return -1 
        
        first = getfirst(data,k)
        end = getend(data,k)
        if first > -1 and end >-1 :
            return end - first + 1
        else:
            return 0
        
        

38、二叉树的深度

题目描述:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

思路:用层次遍历和递归都可以。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def TreeDepth(self, pRoot):
        # write code here
        '''
        if not pRoot:
            return 0
        left = self.TreeDepth(pRoot.left)
        right = self.TreeDepth(pRoot.right)
        return max(left, right) + 1
        '''
        if not pRoot:
            return 0
        tempList = [pRoot]
    	d, count = 0, 0
    	nowLen = len(tempList)
    	while tempList:
    		temp = tempList.pop(0)
    		count += 1
    		if temp.left:
    			tempList.append(temp.left)
    		if temp.right:
    			tempList.append(temp.right)
    		if count == nowLen:
    			d += 1
    			count = 0
    			nowLen = len(tempList)
    	return d
        

39、平衡二叉树

题目描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。 在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树。

思路:平衡二叉树的特点是左右子树的深度差不超过1,我们只要算左右子树的深度就好了

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def IsBalanced_Solution(self, pRoot):
        # write code here
        def TreeDepth(pRoot):
            if not pRoot:
                return 0
            left = TreeDepth(pRoot.left)
            right = TreeDepth(pRoot.right)
            return max(left, right) + 1
        if not pRoot:
            return True
        p_left = TreeDepth(pRoot.left)
        p_right = TreeDepth(pRoot.right)
        ret = abs(p_left - p_right)
        return True if ret <= 1 else False

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

题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

思路:首先:位运算中异或的性质:两个相同数字异或=0,一个数和0异或还是它本身。当只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。

依照这个思路,我们来看两个数(我们假设是AB)出现一次的数组。我们首先还是先异或,剩下的数字肯定是A、B异或的结果,这个结果的二进制中的1,表现的是A和B的不同的位。我们就取第一个1所在的位数,假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。如此,相同的数肯定在一个组,因为相同数字所有位都相同,而不同的数,肯定不在一组。然后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。

|按位或,&按位与, ^ 按位异或

剑指offer刷题_第1张图片

# -*- coding:utf-8 -*-
class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
        # write code here
        if len(array) < 2:
            return None
        xorNum = None
        count = 0
        for num in array:
            if xorNum == None:
                xorNum = num
            else:
                xorNum = xorNum ^ num
        while xorNum % 2 == 0:
            xorNum = xorNum >> 1
            count += 1
        temp = 1 << count
        
        firstNum = None
        secondNum = None
        for num in array:
            if num&temp == 0:
                if firstNum == None:
                    firstNum = num
                else:
                    firstNum = firstNum ^ num
            else:
                if secondNum == None:
                    secondNum = num
                else:
                    secondNum = secondNum ^ num
        return firstNum, secondNum

41、和为S的连续正数序列

题目描述:小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

输出描述:输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

思路:1、直接遍历1-n找出符合条件的序列。 2、双指针技术,就是相当于有一个窗口,窗口的左右两边就是两个指针 2、根据窗口内值之和来确定窗口的位置和宽度。 

# -*- coding:utf-8 -*-
class Solution:
    def FindContinuousSequence(self, tsum):
        # write code here
        # first solution
        '''
        if tsum < 3:
            return []
        ret = []
        for i in range(1, tsum):
            tempSum = 0
            tempArrayList = []
            while tempSum < tsum:
                tempSum += i
                tempArrayList.append(i)
                i += 1
            if tempSum == tsum:
                ret.append(tempArrayList)
        return ret
        '''
        # second solution
        if tsum < 3:
            return []
        ret = []
        leftPointer = 1
        rightPointer = 2
        tempSum = leftPointer + rightPointer
        while rightPointer < tsum:
            if tempSum < tsum:
                rightPointer += 1
                tempSum += rightPointer
            elif tempSum > tsum:
                tempSum -= leftPointer
                leftPointer += 1
            else:
                tempArrayList = []
                for i in range(leftPointer, rightPointer+1):
                    tempArrayList.append(i)
                ret.append(tempArrayList)
                rightPointer += 1
                tempSum += rightPointer
        return ret

42、和为S的两个数字

题目描述:输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

思路:1、遍历数组。2、使用双指针,因为是递增数组,乘积最小的两个数肯定是最外围的两个数。

# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        # first solution
        '''
        a = None
        b = None
        muli = None
        for i in array:
            tempA = i
            tempB = tsum - tempA
            if tempB in array:
                if muli == None or muli > tempA * tempB:
                    a = tempA
                    b = tempB
                    muli = a * b
        if a > b:
            a, b = b, a
        return [] if a == None else [a, b]
        '''
        leftPointer = 0
        rightPointer = len(array) - 1
        ret = []
        while leftPointer < rightPointer:
            tempSum = array[leftPointer] + array[rightPointer]
            if tempSum < tsum:
                leftPointer += 1
            elif tempSum > tsum:
                rightPointer -= 1
            else:
                ret.append(array[leftPointer])
                ret.append(array[rightPointer])
                break
        return ret
            

43、左旋转字符串

题目描述:汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

思路:列表切片。

# -*- coding:utf-8 -*-
class Solution:
    def LeftRotateString(self, s, n):
        # write code here
        return  s[n:] + s[:n]

44、翻转单词顺序列

题目描述:牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

# -*- coding:utf-8 -*-
class Solution:
    def ReverseSentence(self, s):
        # write code here
        
        if not s:
            return ''
        words = s.split(" ")
        words.reverse()
        return ' '.join(w for w in words)
        '''
        return ' '.join(s.split(" ")[::-1])
        '''
        

45、扑克牌顺子

题目描述:LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

思路:题意大概就是,给定五张牌,数值范围是0-13其中0可变为1-13中任意一个数字。你要判断的是这五张牌是否为连续的五个数字。

# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        # write code here
        if len(numbers) != 5:
            return False
        maxNum = -1
        minNum = float("inf")
        for i in numbers:
            if i != 0:
                if i > maxNum:
                    maxNum = i
                if i < minNum:
                    minNum = i
        countZero = numbers.count(0)
        if countZero == 5:
            return True
        if maxNum - minNum > 4:
            return False
        s = [num for num in range(minNum, maxNum + 1)]
        if len(s) + countZero < 5:
            return False
        count = 0
        for i in numbers:
            if i != 0:
                if i in s:
                    count += 1
        return True if count + countZero == 5 else False

46、孩子们的游戏 ***

题目描述:

每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1) 如果没有小朋友,请返回-1

思路:
用数学归纳法推导出递推公式,设有n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。令f[i]表示i个人时最后胜利者的编号,则有递推公式:
f[1]=0;
f[i]=(f[i-1]+m)%i; (i>1)

# -*- coding:utf-8 -*-
class Solution:
    def LastRemaining_Solution(self, n, m):
        # write code here
       # write code here
        #通过推导公式可得 f(n) = (f(n-1)+m)%n
        if n < 1 or m < 1:
            return -1
        #只有一个人的时候,说明要找的就是这一个人。那么就返回下标0 编号。
        if n==1:
            return 0
        value = 0
        #时间复杂度 o(n)
        #从 2 开始 一直到 n 个小朋友 来循环,n 个数,所以为 n+1 
        for index in range(2,n+1):
            #现在数到的 m-1 这个值 的索引。对应上上面的公式。
            currentValue = (value+m) % index
            #把找到的这个下标值 赋值给 value
            value = currentValue
        #返回编号
        return value

47、求1+2+3+...+n **

题目描述:求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

思路:利用短路递归求值,左边的表达式来作为递归结束的判断条件。

# -*- coding:utf-8 -*-
class Solution:
    def Sum_Solution(self, n):
        # write code here
         return n and ( n + self.Sum_Solution(n-1) )

48、不用加减乘除做加法 ***

题目描述:写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

# -*- coding:utf-8 -*-
class Solution:
    def Add(self, num1, num2):
        # write code here
        andNum = (num1 & num2) << 1
        orNum = num1 ^ num2
        while andNum:
            temp1 = (andNum & orNum) << 1
            temp2 = andNum ^ orNum
            temp2 = temp2 & 0xFFFFFFFF
            andNum = temp1
            orNum = temp2
        return orNum if orNum <= 0x7FFFFFFF else ~(orNum ^ 0xFFFFFFFF)

49、把字符串转换成整数

题目描述:将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0

思路:在代码前部分就判定字符串是否为空,头字符是否有正负号,然后遍历的同时判断是否为数字。

# -*- coding:utf-8 -*-
class Solution:
    def StrToInt(self, s):
        # write code here
        if not s:
            return 0
        flag = True
        if s[0] == '+':
            flag = True
            s = s[1:]
        elif s[0] == '-':
            flag = False
            s = s[1:]
        elif not s[0].isdigit():
            return 0
        num = 0
        for i in s:
            if not i.isdigit():
                return 0
            else:
                num = int(i) + 10 * num
        return num if flag else -num

50、数组中重复的数字

题目描述:在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

思路:数组的长度为 n 且所有数字都在 0 到 n-1 的范围内,我们可以将每次遇到的数进行"归位",当某个数发现自己的"位置"被相同的数占了,则出现重复。
扫描整个数组,当扫描到下标为 i 的数字时,首先比较该数字(m)是否等于 i,如果是,则接着扫描下一个数字;如果不是,则拿 m 与第 m 个数比较。如果 m 与第 m 个数相等,则说明出现重复了;如果 m 与第 m 个数不相等,则将 m 与第 m 个数交换,将 m "归位",再重复比较交换的过程,直到发现重复的数

举个例子:
以数组 {2,3,1,0,2,5,3} 为例
当 i = 0 时,nums[i] = 2 != i,判断 nums[i] 不等于 nums[nums[i]],交换 nums[i] 和 nums[nums[i]],交换后数组为:{1,3,2,0,2,5,3}
此时 i = 0,nums[i] = 1 != i,判断 nums[i] 不等于 nums[nums[i]],交换 nums[i] 和 nums[nums[i]],交换后数组为:{3,1,2,0,2,5,3}
此时 i = 0,nums[i] = 3 != i,判断 nums[i] 不等于 nums[nums[i]],交换 nums[i] 和 nums[nums[i]],交换后数组为:{0,1,2,3,2,5,3}
此时 i = 0,nums[i] = 0 = i,继续下一组
当 i = 1,nums[i] = 1 = i,继续下一组
当 i = 2,nums[i] = 2 = i,继续下一组
当 i = 3,nums[i] = 3 = i,继续下一组
当 i = 4,nums[i] = 2 != i,判断 nums[i] 等于 nums[nums[i]],出现重复,赋值返回

时间复杂度:O(n)
空间复杂度:O(1)

# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        duplication[0] = -1
        length = len(numbers)
        if length <= 0 or not numbers:
            return False
        for i in numbers:
            if i < 0 or i > length - 1:
                return False
        for i in range(length):
            while i != numbers[i]:
                if numbers[i] == numbers[numbers[i]]:
                    duplication[0] = numbers[i]
                    return True
                numbers[numbers[i]], numbers[i] = numbers[i], numbers[numbers[i]]
        return False
public class Solution {
    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        duplication[0] = -1;
        if(length <=0 || numbers == null){
            return false;
        }
        for(int i = 0; i < length; i++){
            if(numbers[i] < 0 || numbers[i] > length - 1)
                return false;
        }
        for(int i = 0; i < length; i++){
            while(numbers[i] != i){
                if(numbers[i] == numbers[numbers[i]]){
                    duplication[0] = numbers[i];
                    return true;
                }
                int temp = numbers[i];
                numbers[i] = numbers[temp];
                numbers[temp] = temp;
            }
        }
        return false;
    }
}

51、构建乘积数组

题目描述:B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * ... * A[n-1],B[n-1] = A[0] * A[1] * ... * A[n-2];)

# -*- coding:utf-8 -*-
class Solution:
    def multiply(self, A):
        # write code here
        if not A:
            return []
        B = []
        for i in range(len(A)):
            muli = 1
            temp = A[0:i] + A[i + 1:]
            for j in temp:
                muli *= j
            B.append(muli)
        return B

52、正则表达式匹配 ***

题目描述:请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配

思路:动态规划https://leetcode-cn.com/problems/regular-expression-matching/solution/dong-tai-gui-hua-zen-yao-cong-0kai-shi-si-kao-da-b/

  • 如果 p.charAt ( j ) == s.charAt ( i ) : dp[i][j] = dp[i-1][j-1]; 
  • 如果 p.charAt ( j ) == '.' : dp[i][j] = dp[i-1][j-1]; 
  • 如果 p.charAt ( j ) == '*':
    1. 如果 p.charAt ( j - 1 ) != s.charAt ( i ) : dp[i][j] = dp[i][j-2] //in this case, a* only counts as empty,e.g.b&ba*
    2. 如果 p.charAt ( j - 1 ) == s.charAt ( i ) or p.charAt (j-1) == '.': 
      1. dp [i] [j] = dp [i-1] [j] //in this case, a* counts as multiple a , e.g.baaa&ba*
      2. or dp [i] [j] = dp [i] [j-1] // in this case, a* counts as single a, e.g.ba&ba*(注意这个条件可以忽略,它等价于dp [i-1] [j] = dp [i-1] [j-2] 的情形,即b&ba*) 
      3. or dp [i] [j] = dp [i] [j-2] // in this case, a* counts as empty, e.g.ba&baa*
# -*- coding:utf-8 -*-
class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # write code here
        ls, lp = len(s), len(pattern)
        dp = [[False for _ in range(lp + 1)] for _ in range(ls + 1)]
        dp[0][0] = True
        for i in range(1, lp + 1):
            if i - 2 >= 0 and pattern[i - 1] == '*':
                dp[0][i] = dp[0][i - 2]
        for i in range(1, ls + 1):
            for j in range(1, lp + 1):
                m, n = i - 1, j - 1
                if pattern[n] == '*':
                    if s[m] == pattern[n - 1] or pattern[n - 1] == '.':
                        dp[i][j] = dp[i][j - 2] or dp[i - 1][j]
                    else: dp[i][j] = dp[i][j - 2]
                elif s[m] == pattern[n] or pattern[n] == '.':
                    dp[i][j] = dp[i - 1][j - 1]
        return dp[-1][-1]

53、表示数值的字符串 ***

题目描述:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

思路:https://leetcode-cn.com/problems/biao-shi-shu-zhi-de-zi-fu-chuan-lcof/solution/onpythonjie-ti-wu-fa-luo-ji-pan-duan-regexdfadeng-/

使用3个标志位met_dot, met_e, met_digit来分别标记是否遇到了“.”,“e/E”和任何0-9的数字。当然首先要去掉首位的空格。

# -*- coding:utf-8 -*-
class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        s = s.strip()
        met_dot = met_e = met_digit = False
        for i, char in enumerate(s):
            if char in ('+', '-'):
                if i > 0 and s[i-1] != 'e' and s[i-1] != 'E':
                    return False
            elif char == '.':
                if met_dot or met_e: 
                    return False
                met_dot = True
            elif char == 'e' or char == 'E':
                if met_e or not met_digit:
                    return False
                met_e, met_digit = True, False # e后必须接,所以这时重置met_digit为False,以免e为最后一个char
            elif char.isdigit():
                met_digit = True
            else:
                return False
        return met_digit

54、字符流中第一个不重复的字符

题目描述:

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。如果当前字符流没有存在出现一次的字符,返回#字符。

思路:定义两个列表str和firstOne,分别存储字符流和当前长度字符流第一次出现的字符。

# -*- coding:utf-8 -*-
class Solution:
    # 返回对应char
    def __init__(self):
        self.firstOne = []
        self.str = []
    def FirstAppearingOnce(self):
        # write code here
        return self.firstOne[-1]
    def Insert(self, char):
        # write code here
        self.str.append(char)
        flag = False
        for i, num in enumerate(self.str):
               if num not in self.str[0:i] + self.str[i+1:]:
                    self.firstOne.append(num)
                    flag = True
                    break
        if not flag:
            self.firstOne.append('#')

55、链表中环的入口节点 ***

题目描述:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

思路:第一种思路是遍历一遍链表,在遍历的同时把走过的节点保存在一个列表里面,遍历遇见的第一个重复的即为入口节点,这个节点就是入口节点。

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

  1. 这题我们可以采用双指针解法,一快一慢指针。快指针每次跑两个element,慢指针每次跑一个。如果存在一个圈,总有一天,快指针是能追上慢指针的。 
  2. 如下图所示,我们先找到快慢指针相遇的点,p。我们再假设,环的入口在点q,从头节点到点q距离为A,q p两点间距离为B,p q两点间距离为C。 
  3. 因为快指针是慢指针的两倍速,且他们在p点相遇,则我们可以得到等式 2(A+B) = A+B+C+B. 
  4. 由3的等式,我们可得,C = A。 
  5. 这时,因为我们的slow指针已经在p,我们可以新建一个另外的指针,slow2,让他从头节点开始走,每次只走下一个,原slow指针继续保持原来的走法,和slow2同样,每次只走下一个。 
  6. 我们期待着slow2和原slow指针的相遇,因为我们知道A=C,所以当他们相遇的点,一定是q了。 
  7. 我们返回slow2或者slow任意一个节点即可,因为此刻他们指向的是同一个节点,即环的起始点,q。 

剑指offer刷题_第2张图片

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        # first solution
        '''
        p = pHead
        tempList = []
        if p == None:
            return None
        while p:
            if p in tempList:
                return p
            tempList.append(p)
            p = p.next
        if p == None:
            return None
        '''
        # second solution
        if pHead == None:
            return None
        fastNode = pHead
        slowNode = pHead
        while fastNode and fastNode.next:
            fastNode = fastNode.next.next
            slowNode = slowNode.next
            if fastNode == slowNode:
                break
        if fastNode == None or fastNode.next == None:
            return None
        fastNode = pHead
        while fastNode != slowNode:
            fastNode = fastNode.next
            slowNode = slowNode.next
        return fastNode
        

56、删除链表中重复的结点

题目描述:在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

思路:这代码纯粹是在错误中慢慢调出来的。。。。首先第一个while大循环是为删除链表最开始的重复节点,保证第一个节点不重复。后面就是普遍的pre指针存储当前节点的前一个节点,碰到重复的节点直接while循环到不重复的节点,最后pre的next节点指向cur的next节点。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        if not pHead or not pHead.next:
            return pHead
        pre = pHead
        cur = pHead.next
        while True:
            if cur and pre.val == cur.val:
                flag = False
                while pre.val == cur.val:
                    flag = True
                    cur = cur.next
                    if not cur:
                        return None
                if flag:
                    pre = cur
                    cur = pre.next
            else:
                break
        ret = pre
        while cur:
            if cur.next and cur and cur.val == cur.next.val:
                flag = False
                while cur.val == cur.next.val:
                    flag = True
                    cur = cur.next
                    if not cur.next:
                        break
                if flag:
                    pre.next = cur.next
                    cur = cur.next
            else:
                pre = cur
                cur = cur.next
        return ret

57、二叉树的下一个节点 ***

题目描述:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

# -*- coding:utf-8 -*-
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None
class Solution:
    def GetNext(self, pNode):
        # write code here
        if pNode == None:
            return None
        if pNode.right:
            pNode = pNode.right
            while pNode.left:
                pNode = pNode.left
            pNext = pNode
        else:
            pCurrent = pNode
            pParent = pNode.next
            while pParent and pCurrent == pParent.right:
                pCurrent = pParent
                pParent = pParent.next
            pNext = pParent
        return pNext

58、对称的二叉树 ***

题目描述:请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

思路:首先我们检测根节点的左孩子和右孩子,如果两个都是null,说明他是镜像。但是如果有一个不为null或者他们的值不相等,则此时我们就可以判断已经是不对称的了。如果此时还是对称的而且左孩子和右孩子都分别还有各自的孩子,我们就继续检测。这时,我们需要判断,左孩子的左子树和右孩子的右子树是否镜像,及左孩子的右子树和右孩子的左子树是否镜像。

剑指offer刷题_第3张图片

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        def judge(left, right):
            if not left and not right:
                return True
            if not left or not right:
                return False
            if left.val == right.val:
                return judge(left.left, right.right) and judge(left.right, right.left)
        if not pRoot:
            return True
        else:
            return judge(pRoot.left, pRoot.right)

59、按之字形顺序打印二叉树 ***

题目描述:请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

思路:

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Print(self, pRoot):
        # write code here
        if pRoot == None:
            return []
        stack1 = [pRoot]
        stack2 = []
        Ret = []
        while stack1 or stack2:
            if stack1:
                tempRet = []
                while stack1:
                    tempNode = stack1.pop()
                    if tempNode.left:
                        stack2.append(tempNode.left)
                    if tempNode.right:
                        stack2.append(tempNode.right)
                    tempRet.append(tempNode.val)
                Ret.append(tempRet)
            if stack2:
                tempRet = []
                while stack2:
                    tempNode = stack2.pop()
                    if tempNode.right:
                        stack1.append(tempNode.right)
                    if tempNode.left:
                        stack1.append(tempNode.left)
                    tempRet.append(tempNode.val)
                Ret.append(tempRet)
        return Ret
                    

60、把二叉树打印成多行

题目描述:从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表[[1,2],[4,5]]
    def Print(self, pRoot):
        # write code here
        if pRoot == None:
            return []
        queue1 = [pRoot]
        queue2 = []
        Ret = []
        while queue1 or queue2:
            if queue1:
                tempRet = []
                while queue1:
                    tempNode = queue1.pop()
                    if tempNode.left:
                        queue2.insert(0, tempNode.left)
                    if tempNode.right:
                        queue2.insert(0, tempNode.right)
                    tempRet.append(tempNode.val)
                Ret.append(tempRet)
            if queue2:
                tempRet = []
                while queue2:
                    tempNode = queue2.pop()
                    if tempNode.left:
                        queue1.insert(0, tempNode.left)
                    if tempNode.right:
                        queue1.insert(0, tempNode.right)
                    tempRet.append(tempNode.val)
                Ret.append(tempRet)
        return Ret

61、序列化二叉树

题目描述:

请实现两个函数,分别用来序列化和反序列化二叉树 

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
例如,我们可以把一个只有根节点为1的二叉树序列化为"1,",然后通过自己的函数来解析回这个二叉树

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    
    ss = []
    def Serialize(self, root):
        # write code here
        if root is None:
            return '#,'
        return str(root.val) +','+ self.Serialize(root.left) + self.Serialize(root.right)
               
    def Deserialize(self, s):
        # write code here
        if len(s)==0:
            return None
        if s[0] == '#':
            return None
        self.ss = s.split(',')
        return self.reconstruct()


    def reconstruct(self):
        val = self.ss[0]
        if val == '#':
            self.ss = self.ss[1:]
            return None
        val = int(val)
        root = TreeNode(val)
        self.ss = self.ss[1:]
        root.left = self.reconstruct()
        root.right = self.reconstruct()
        return root
    '''
    def Serialize(self, root):
        retList = []
        def preOrder(root):
            if root == None:
                retList.append('#')
                return
            retList.append(str(root.val))
            preOrder(root.left)
            preOrder(root.right)
        preOrder(root)
        return ' '.join(retList)
    
    
    def Deserialize(self, s):
        retList = s.split()
        def dePreOrder():
            if retList == []:
                return None
            rootVal = retList[0]
            del retList[0]
            if rootVal == '#':
                return None
            node = TreeNode(int(rootVal))
        
            leftNode = dePreOrder()
            rightNode = dePreOrder()
            return node
        
        pRoot = dePreOrder
        return pRoot
        '''

62、二叉搜索树的第k个节点

题目描述:给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8)    中,按结点数值大小顺序第三小结点的值为4。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回对应节点TreeNode
    def KthNode(self, pRoot, k):
        # write code here
        if k <= 0 or pRoot == None:
            return None
        tempNode = pRoot
        stack = []
        Ret = []
        while stack or tempNode:
            while tempNode:
                stack.append(tempNode)
                tempNode = tempNode.left
            temp = stack.pop()
            Ret.append(temp)
            if len(Ret) == k:
                return Ret[-1]
            if temp.right != None:
                tempNode = temp.right
                

63、数据流的中位数

题目描述:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.littleValueMaxHeap = []
        self.bigValueMinHeap = []
        self.maxHeapCount = 0
        self.minHeapCount = 0
        
    def Insert(self, num):
        def cmpMaxHeap(a, b):
            return a > b
        def cmpMinHeap(a, b):
            return a < b
        if self.maxHeapCount > self.minHeapCount:
            self.minHeapCount += 1
            if num < self.littleValueMaxHeap[0]:
                tmpNum = self.littleValueMaxHeap[0]
                self.adjustHeap(num, self.littleValueMaxHeap, cmpMaxHeap)
                self.createHeap(tmpNum, self.bigValueMinHeap, cmpMinHeap)
            else:
                self.createHeap(num, self.bigValueMinHeap, cmpMinHeap)
        else:
            self.maxHeapCount += 1
            if len(self.littleValueMaxHeap) == 0:
                self.createHeap(num, self.littleValueMaxHeap, cmpMaxHeap)
            else:
                if self.bigValueMinHeap[0] < num:
                    tempNum = self.bigValueMinHeap[0]
                    self.adjustHeap(num, self.bigValueMinHeap, cmpMinHeap)
                    self.createHeap(tempNum, self.littleValueMaxHeap, cmpMaxHeap)
                else:
                    self.createHeap(num, self.littleValueMaxHeap, cmpMaxHeap)
                
            
        # write code here
    def GetMedian(self, n=None):
        # write code here
        if self.minHeapCount < self.maxHeapCount:
            return self.littleValueMaxHeap[0]
        else:
            return (float)(self.littleValueMaxHeap[0] + self.bigValueMinHeap[0]) / 2
    def createHeap(self, num, heap, cmpfun):
        heap.append(num)
        tmpIndex = len(heap) - 1
        while tmpIndex:
            parentIndex = (tmpIndex - 1) // 2
            if cmpfun(heap[tmpIndex], heap[parentIndex]):
                heap[parentIndex], heap[tmpIndex] = heap[tmpIndex], heap[parentIndex]
                tmpIndex = parentIndex
            else:
                break
    
    def adjustHeap(self, num, heap, cmpFunc):
        if num < heap[0]:
            maxHeapLen = len(heap)
            heap[0] = num
            tmpIndex = 0
            while tmpIndex < maxHeapLen:
                leftIndex = tmpIndex * 2 + 1
                rightIndex = tmpIndex * 2 + 2
                largerIndex = 0
                if rightIndex < maxHeapLen:
                    largerIndex = rightIndex if cmpFunc(heap[rightIndex], heap[leftIndex]) else leftIndex
                elif leftIndex < maxHeapLen:
                    largerIndex = leftIndex
                else:
                    break
                
                if cmpFunc(heap[largerIndex], heap[tmpIndex]):
                    heap[largerIndex], heap[tmpIndex] = heap[tmpIndex], heap[largerIndex]
                    tmpIndex = largerIndex
                else:
                    break

64、滑动窗口的最大值

题目描述:给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

思路:我用的是列表切片,求列表的最大值。

# -*- coding:utf-8 -*-
class Solution:
    def maxInWindows(self, num, size):
        # write code here
        if len(num) < size or len(num) == 0 or size <= 0:
            return []
        ret = []
        for i in range(len(num) - size + 1):
            temp = num[i:i + size]
            tempMax = max(temp)
            ret.append(tempMax)
        return ret

65、矩阵中的路径

题目描述:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如剑指offer刷题_第4张图片 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self._dict = {}
    def hasPath(self, matrix, rows, cols, path):
        # write code here
        if matrix == None or rows < 1 or cols < 1 or path == None:
            return False
        x = [list(matrix[i*cols:(i+1)*cols]) for i in range(rows)]
        for i in range(rows):
            for j in range(cols):
                self._dict = {}
                if self.dfs(x, i, j, path):
                    return True
        return False
    def dfs(self, matrix, i, j, p):

        if not (0 <= i< len(matrix) and 0 <= j < len(matrix[0])):  # 越界
            return False
        if matrix[i][j] != p[0]:  # 不匹配
            return False
        if self._dict.get((i,j)) is not None:  # 重复路径
            return False
        self._dict[(i,j)] = 1
        if not p[1:]:
            return True
        # 向上下左右寻找
        return self.dfs(matrix,i+1,j,p[1:]) or self.dfs(matrix,i-1,j,p[1:]) or self.dfs(matrix,i,j+1,p[1:]) or self.dfs(matrix,i,j-1,p[1:])

66、机器人运动范围

问题描述:地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

思路:参考https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/上面的解析

# -*- coding:utf-8 -*-
class Solution:
    def movingCount(self, threshold, rows, cols):
        # write code here
        def dfs(i, j, si, sj):
            if i >= rows or j >= cols or threshold < si + sj or (i, j) in visited: return 0
            visited.add((i,j))
            return 1 + dfs(i + 1, j, si + 1 if (i + 1) % 10 else si - 8, sj) + dfs(i, j + 1, si, sj + 1 if (j + 1) % 10 else sj - 8)
        visited = set()
        return dfs(0, 0, 0, 0)

67、剪绳子

题目描述:给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m]。请问k[0]xk[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

思路:剑指offer上面的贪婪算法

# -*- coding:utf-8 -*-
class Solution:
    def cutRope(self, number):
        # write code here
        if number < 2:
            return 0
        if number == 2:
            return 1
        if number == 3:
            return 2       
        timesOf3 = number / 3
        if (number - timesOf3*3) == 1:
            timesOf3 -= 1
        timesOf2 = (number - timesOf3*3) / 2
        return pow(3, timesOf3)*pow(2, timesOf2)

 

你可能感兴趣的:(剑指offer刷题)