剑指offer的python解答合集(更新完毕)

20190130:被疫情困在家里,没事刷刷剑指offer的题目,这里写一个题解合集,还没更完,搞定15道
20190206:28道啦
20190211:46道
20190215:61道
20190216:全部更完

文章目录

    • 第二章
      • 面试题3:数组中重复的数字
      • 面试题4:二维数组中查找
      • 面试题5:替换空格
      • 面试题6:从尾到头打印链表
      • 面试题7:重建二叉树
      • 面试题8:二叉树的下一个节点
      • 面试题9:用两个栈实现队列
      • 面试题10:斐波那契数列
      • 面试题11:旋转数组的最小数字
      • 面试题12:矩阵中的路径
      • 面试题13:机器人的运动范围
      • 面试题14:剪绳子
      • 面试题15:二进制中1的个数
    • 第三章
      • 面试题16:数值的整数次方
      • 面试题17:打印从1到最大的n位数
      • 面试题18:删除链表的节点
      • 面试题19:正则表达式匹配
      • 面试题20:表示数值的字符串
      • 面试题21:调整数组顺序使奇数位于偶数前面
      • 面试题22:链表中倒数第k个节点
      • 面试题23:链表中环的入口节点
      • 面试题24:反转链表
      • 面试题25:合并两个排序的链表
      • 面试题26:树的子结构
    • 第四章
      • 面试题27:二叉树的镜像
      • 面试题28:对称的二叉树
      • 面试题29:顺时针打印矩阵
      • 面试题30:包含min函数的栈
      • 面试题31:栈的压入、弹出序列
      • 面试题32:从上到下打印二叉树
      • 面试题33:二叉搜索树的后序遍历序列
      • 面试题34:二叉树中和为某一值的路径
      • 面试题35:复杂链表的复制
      • 面试题36:二叉搜索树与双向链表
      • 面试题37:序列化二叉树
      • 面试题38:字符串的排列
    • 第五章
      • 面试题39:数组中出现次数超过一半的数字
      • 面试题40:最小的k个数
      • 面试题41:数据流中的中位数
      • 面试题42:连续子数组的最大和
      • 面试题43:1 ~ n整数中1出现的次数
      • 面试题44:数字序列中某一位的数字
      • 面试题45:把数组排成最小的数
      • 面试题46:把数字翻译成字符串
      • 面试题47:礼物的最大价值
      • 面试题48:最长不含重复字符的子字符串
      • 面试题49:丑数
      • 面试题50:第一个只出现一次的字符
      • 面试题51:数组中的逆序对
      • 面试题52:两个链表的第一个公共节点
    • 第六章
      • 面试题53:在排序数组中查找数字
      • 面试题54:二叉搜索树的第K大(小)节点
      • 面试题55:二叉树的深度
      • 面试题56:数组中数字出现的次数
      • 面试题57:和为s的数字
      • 面试题58:翻转字符串
      • 面试题59:队列的最大值
      • 面试题60:n个骰子的点数
      • 面试题61:扑克牌中的顺子
      • 面试题62:圆圈中最后剩下的数字
      • 面试题63:股票的最大利润
      • 面试题64:求1+2+……+n
      • 面试题65:不用加减乘除做加法
      • 面试题66:构建乘积数组

第二章

面试题3:数组中重复的数字

  • 题目描述
    在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        for i, m in enumerate(numbers):
            if i == m:
                continue
            else:
                if numbers[m] == m:
                    duplication[0] = m
                    return True
                else:
                    numbers[i] = numbers[m]
                    numbers[m] = m
        return False

面试题4:二维数组中查找

  • 题目描述
    在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        i = len(array) - 1
        j = 0
        while i!=0 or j != len(array[0]) - 1:
            if i < 0 or j > len(array[0]) - 1:
                return False
            n = array[i][j]
            if n > target:
                i -= 1
            elif n < target:
                j += 1
            else:
                return True

面试题5:替换空格

  • 题目描述
    请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        s = s.replace(' ', '%20')
        return s

面试题6:从尾到头打印链表

  • 题目描述
    输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
# -*- 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
        re = []
        while listNode:
            re.append(listNode.val)
            listNode = listNode.next
        return re[::-1]

面试题7:重建二叉树

  • 题目描述
    输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{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
        root_val = pre[0]
        root = TreeNode(root_val)
        idx = tin.index(root_val)
        if idx == 0:
            left_tree = None
        else:
            left_tree = self.reConstructBinaryTree(pre[1:idx+1], tin[:idx])
        if idx == len(pre) - 1:
            right_tree = None
        else:
            right_tree = self.reConstructBinaryTree(pre[idx+1:], tin[idx+1:])
        root.left = left_tree
        root.right = right_tree
        return root

面试题8:二叉树的下一个节点

  • 题目描述
    给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
# -*- 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.right:
            pNode = pNode.right
            while pNode.left:
                pNode = pNode.left
            return pNode
        while pNode:
            if pNode.next:
                if pNode.next.left == pNode:
                    return pNode.next
                pNode = pNode.next
            else:
                return None

面试题9:用两个栈实现队列

  • 题目描述
    用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
        
    def push(self, node):
        # write code here
        while self.stack2:
            self.stack1.append(self.stack2.pop())
        self.stack1.append(node)
        
    def pop(self):
        # return xx
        while self.stack1:
            self.stack2.append(self.stack1.pop())
        return self.stack2.pop()

面试题10:斐波那契数列

  • 题目描述
    大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
    n<=39
# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        # write code here
        if n <= 0:
            return 0
        if n == 1:
            return 1
        i = 2
        a, b = 0, 1
        while i <= n:
            s = a + b
            a, b = b, s
            i += 1
        return s

面试题11:旋转数组的最小数字

  • 题目描述
    把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
    输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
    例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
    NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if not rotateArray:
            return 0
        left = 0
        right = len(rotateArray) - 1
        while left < right:
            if rotateArray[left]<rotateArray[right]:
                return rotateArray[left]
            mid = (right + left) // 2
            if rotateArray[left] < rotateArray[mid]:
                left = mid
            elif rotateArray[mid] > rotateArray[right]:
                right = mid
            else:
                right -= 1
        return rotateArray[mid+1]

面试题12:矩阵中的路径

  • 题目描述
    请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 a b c e s f c s a d e e 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
# -*- coding:utf-8 -*-
class Solution:
    def hasPath(self, matrix, rows, cols, path):
        # write code here
        for i in range(len(matrix)):
            if matrix[i] == path[0]:
                if self.isPath(matrix, rows, cols, i, path):
                    return True
        return False
    
    def isPath(self, matrix, rows, cols, i, path):
        if matrix[i] != path[0]:
            return False
        if len(path) == 1:
            return True
        # 可以设置一个矩阵,来标志某一格子是否已经被走过
        matrix = matrix[:i] + '#' + matrix[i+1:]
        up = self.isPath(matrix, rows, cols, i-cols, path[1:]) if i >= cols else False
        down = self.isPath(matrix, rows, cols, i+cols, path[1:]) if i < len(matrix) - cols else False
        right = self.isPath(matrix, rows, cols, i+1, path[1:]) if ((i+1) % cols != cols and i+1 < len(matrix)) else False
        left = self.isPath(matrix, rows, cols, i-1, path[1:]) if (i % cols != cols and i-1>0) else False
        return up or down or left or right

面试题13:机器人的运动范围

  • 题目描述
    地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
# -*- coding:utf-8 -*-
class Solution:
    def movingCount(self, threshold, rows, cols):
        # write code here
        return len(self.spaceCount(set(), 0, 0, threshold, rows, cols))
        
    def spaceCount(self, re, i, j, threshold, rows, cols):
        if self.get_bitsum(i) + self.get_bitsum(j) > threshold or (i, j) in re:
            return re
        re.add((i,j))
        if i + 1 < rows:
            re = self.spaceCount(re, i+1, j, threshold, rows, cols)
        if j + 1 < cols:
            re = self.spaceCount(re, i, j+1, threshold, rows, cols)
        return re

    def get_bitsum(self, num):
        s = 0
        while num>0:
            s += num % 10
            num = num // 10
        return s

面试题14:剪绳子

  • 题目描述
    给你一根长度为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。
# -*- 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
        products = [0, 1, 2, 3]
        for i in range(4, number+1, 1):
            product = 0
            for j in range(1,i//2+1):
                res = products[j]* products[i-j]
                product = max(res,product)
                products.append(product)
        return products[-1]

面试题15:二进制中1的个数

  • 题目描述
    输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        count=0
        if n < 0:
            n = n & 0xffffffff
        while n!=0:
            n=n&(n-1)
            count+=1
        return count

第三章

面试题16:数值的整数次方

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

解法一:

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        return self.PosPower(base, exponent) if exponent >= 0 else 1 / self.PosPower(base, -exponent)
         
    def PosPower(self, base, exponent):
        re = 1
        for i in range(exponent):
            re *= base
        return re

解法二:

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        return self.PosPower(base, exponent) if exponent >= 0 else 1 / self.PosPower(base, -exponent)
        
    def PosPower(self, base, exponent):
        if exponent == 0:
            return 1
        if exponent == 1:
            return base
        re_half = self.PosPower(base, exponent//2)
        if exponent % 2 == 0:
            re = re_half * re_half
        else:
            re = re_half * re_half * base
        return re

面试题17:打印从1到最大的n位数

解法一:

n = 3

def strAdd1(number):
    length = len(number)
    for i in range(length):
        n = ord(number[-i-1]) - ord('0')
        if n != 9:
            bit = chr(n+1+ord('0'))
            number = number[:-i-1] + bit + ''.join(['0']*i)
            return number
    return '1' + ''.join(['0']*length)

number = '0'
last_number = ''.join(['9']*n)
print(number)
while number != last_number:
    number = strAdd1(number)
    print(number)

解法二:

n = 3
def printN(pre, length):
    if length == 0:
        print(pre)
        return
    for i in range(10):
        printN(pre+str(i), length-1)
    return

for i in range(n):
    if i == 0:
        printN('', i + 1)
    else:
        for j in range(1,10):
            printN(str(j), i)

面试题18:删除链表的节点

  • 题目描述
    在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        def deleteHeadDuplication(pHead):
            while pHead.next.val == pHead.val:
                pHead.next = pHead.next.next
                if not pHead.next:
                    return None
            return pHead.next
        
        if not pHead or not pHead.next:
            return pHead
        re = ListNode(0)
        re.next = pHead
        cur = re
        while cur.next and cur.next.next:
            if cur.next.val == cur.next.next.val:
                cur.next = deleteHeadDuplication(cur.next)
            else:
                cur = cur.next
        return re.next

面试题19:正则表达式匹配

  • 题目描述
    请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配
    (这题为什么有详细注释:太复杂了我抄了答案)
# -*- coding:utf-8 -*-
class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # 如果s与pattern都为空,则True
        if len(s) == 0 and len(pattern) == 0:
            return True
        # 如果s不为空,而pattern为空,则False
        elif len(s) != 0 and len(pattern) == 0:
            return False
        # 如果s为空,而pattern不为空,则需要判断
        elif len(s) == 0 and len(pattern) != 0:
            # pattern中的第二个字符为*,则pattern后移两位继续比较
            if len(pattern) > 1 and pattern[1] == '*':
                return self.match(s, pattern[2:])
            else:
                return False
        # s与pattern都不为空的情况
        else:
            # pattern的第二个字符为*的情况
            if len(pattern) > 1 and pattern[1] == '*':
                # s与pattern的第一个元素不同,则s不变,pattern后移两位,相当于pattern前两位当成空
                if s[0] != pattern[0] and pattern[0] != '.':
                    return self.match(s, pattern[2:])
                else:
                    # 如果s[0]与pattern[0]相同,且pattern[1]为*,这个时候有三种情况
                    # pattern后移2个,s不变;相当于把pattern前两位当成空,匹配后面的
                    # pattern后移2个,s后移1个;相当于pattern前两位与s[0]匹配
                    # pattern不变,s后移1个;相当于pattern前两位,与s中的多位进行匹配,因为*可以匹配多位
                    return self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern)
            # pattern第二个字符不为*的情况
            else:
                if s[0] == pattern[0] or pattern[0] == '.':
                    return self.match(s[1:], pattern[1:])
                else:
                    return False

面试题20:表示数值的字符串

  • 题目描述
    请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。(再次无耻地抄了答案)
# -*- coding:utf-8 -*-
import re
class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        return re.match(r"^[\+\-]?[0-9]*(\.[0-9]*)?([eE][\+\-]?[0-9]+)?$",s)

面试题21:调整数组顺序使奇数位于偶数前面

  • 题目描述
    输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        # write code here
        return sorted(array,key=lambda c:c%2,reverse=True)

面试题22:链表中倒数第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
        if not head or k <= 0:
            return None
        fast = head
        slow = head
        for i in range(k):
            if not fast:
                return None
            fast = fast.next
        while fast:
            slow = slow.next
            fast = fast.next
        return slow

面试题23:链表中环的入口节点

  • 题目描述
    给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        # 判断是否有环
        def hasCycle(head):
            slow = head
            fast = head
            i = 0
            while fast:
                fast = fast.next
                if i % 2 != 0:
                    slow = slow.next
                if fast == slow:
                    return True, fast
                i += 1
            return False, None
        
        # 无环则返None
        hasCycle, cyclePoint = hasCycle(head)
        if not hasCycle:
            return None
        # 计算环的周长l
        count = 1
        cur = cyclePoint.next
        while cur != cyclePoint:
            cur = cur.next
            count += 1
        # 后一个指针移动l步
        cur = head
        for i in range(count):
            cur = cur.next
        # 前后指针同步移动,找到环的入口
        count = 0
        while head != cur:
            head = head.next
            cur = cur.next
            count += 1
        return head

面试题24:反转链表

  • 题目描述
    输入一个链表,反转链表后,输出新链表的表头。
# -*- 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
        def ReverseAndTail(pHead):
            if not pHead.next:
                return pHead, pHead
            pAfter, tail = ReverseAndTail(pHead.next)
            pHead.next = None
            tail.next = pHead
            return pAfter, pHead
        if not pHead:
            return None
        else:
            pHead, _ = ReverseAndTail(pHead)
            return pHead

面试题25:合并两个排序的链表

  • 题目描述
    输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
# -*- 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 not pHead1:
            return pHead2
        if not pHead2:
            return pHead1
        re = ListNode(0)	# 添加一个哨兵节点
        re.next = pHead1
        pHead1 = re
        temp = ListNode(0)	# 使用temp变量保存要插入的节点
        while pHead1.next:
            if pHead2.val <= pHead1.next.val:
                temp.next = pHead2	# 使用temp变量保存要插入的节点
                pHead2 = pHead2.next
                temp.next.next = pHead1.next	# 修改插入节点的指针
                pHead1.next = temp.next	# 将插入节点插进去
            pHead1 = pHead1.next
            if not pHead2:	# 若链表2全部插入链表1
                break
        if pHead2:	# 若链表2未全部插入链表1
            pHead1.next = pHead2
        return re.next

面试题26:树的子结构

  • 题目描述
    输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
# -*- 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
        # 判断pRoot2是否为pRoot1同根的子树
        def IsSameRootTree(pRoot1, pRoot2):
            if not pRoot2:    # 判断pRoot2是否已经匹配完
                return True
            if not pRoot1:    # 若pRoot2未匹配完,而pRoot1已经匹配完了,则返回False
                return False
            return pRoot1.val == pRoot2.val and IsSameRootTree(pRoot1.left, pRoot2.left) and IsSameRootTree(pRoot1.right, pRoot2.right)
        
        if not pRoot1 or not pRoot2:
            return False
        return IsSameRootTree(pRoot1, pRoot2) or self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)

第四章

面试题27:二叉树的镜像

  • 题目描述
    操作给定的二叉树,将其变换为源二叉树的镜像。
# -*- 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 not root:
            return root
        root.left, root.right = self.Mirror(root.right), self.Mirror(root.left)
        return root

面试题28:对称的二叉树

  • 题目描述
    请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
# -*- 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
        if not pRoot:
            return True
        return self.isMirror(pRoot.left, pRoot.right)
        
    def isMirror(self, left, right):
        if not left and not right:
            return True
        elif left and right:
            center = self.isMirror(left.right, right.left)
            side = self.isMirror(left.left, right.right)
            return center and side and left.val == right.val
        else:
            return False

面试题29:顺时针打印矩阵

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

# -*- coding:utf-8 -*-
class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        # write code here
        rows = len(matrix)
        cols = len(matrix[0])
        if rows == 0:
            return []
        re = []
        i = 0
        while True:
            if i > rows - i - 1 or i > cols - i - 1:
                break
            if i == rows - i - 1:
                re += matrix[i][i:cols - i]
                break
            if i == cols - i - 1:
                re += [x[i] for x in matrix[i:rows - i]]
                break
            # if i + 1 == rows - i - 1:
            #     re += matrix[i][i:i + 2] + matrix[i + 1][i:i + 2][::-1]
            #     break
            re += matrix[i][i:cols - i]
            re += [x[cols - i - 1] for x in matrix[i + 1:rows - i - 1]]
            re += matrix[rows - i - 1][i:cols - i][::-1]
            re += [x[i] for x in matrix[i + 1:rows - i - 1]][::-1]
            i += 1
        return re

面试题30:包含min函数的栈

  • 题目描述
    定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack = []
        self.assist_stack = []
        
    def push(self, node):
        # write code here
        self.stack.append(node)
        if not self.assist_stack:
            self.assist_stack.append(node)
        else:
            if node <= self.assist_stack[-1]:
                self.assist_stack.append(node)
        return
        
    def pop(self):
        # write code here
        if self.stack:
            if self.stack[-1] == self.assist_stack[-1]:
                self.assist_stack.pop()
            return self.stack.pop()
        else:
            return None
        
    def top(self):
        # write code here
        if self.stack:
            return self.stack[-1]
        else:
            return None
        
    def min(self):
        # write code here
        if not self.assist_stack:
            return None
        return self.assist_stack[-1] 

面试题31:栈的压入、弹出序列

  • 题目描述
    输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列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 sorted(pushV) != sorted(popV):
            return False
        stack = []
        re = []
        i = 0
        while i < len(popV):
            if not pushV and stack:
                return False
            if not stack or stack[-1] != popV[i]:
                stack += pushV[:pushV.index(popV[i]) + 1]
                pushV = pushV[pushV.index(popV[i]) + 1:]
            while stack and stack[-1] == popV[i]:
                re.append(stack.pop())
                i += 1
        return re == popV

面试题32:从上到下打印二叉树

  • 题目描述
# -*- 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 not root:
            return []
        re = []
        queue = [root]
        while queue:
            tree = queue.pop(0)
            re.append(tree.val)
            if tree.left:
                queue.append(tree.left)
            if tree.right:
                queue.append(tree.right)
        return re

面试题33:二叉搜索树的后序遍历序列

  • 题目描述
    输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if not sequence:
            return False
        # 找到左右子树的分割点
        i = 0
        while sequence[i] < sequence[-1]:
            i += 1
        # 检查左树是否BST
        if i == 0:
            left_BST = True
        else:
            left_BST = self.VerifySquenceOfBST(sequence[:i])
        # 检查右树是否BST,且都大于根节点
        if i == len(sequence) - 1:
            right_BST = True
        elif min(sequence[i:-1]) < sequence[-1]:
            right_BST = False
        else:
            right_BST = self.VerifySquenceOfBST(sequence[i:-1])
        # 返回节点
        return True if left_BST and right_BST else False

面试题34:二叉树中和为某一值的路径

  • 题目描述
    输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
# -*- coding:utf-8 -*-
# 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
        re = []
        paths = self.FindPathSum(root)
        for path in paths:
            if sum(path) == expectNumber:
                re.append(path)
        return re

    def FindPathSum(self, root):
        if not root:
            return []
        if not root.left and not root.right:
            return [[root.val]]
        re = []
        leftSum = self.FindPathSum(root.left)
        rightSum = self.FindPathSum(root.right)
        while leftSum and rightSum:
            if len(leftSum[0]) > len(rightSum[0]):
                re.append([root.val] + leftSum[0])
                leftSum.pop(0)
            else:
                re.append([root.val] + rightSum[0])
                rightSum.pop(0)
        if leftSum:
            re += [[root.val] + x for x in leftSum]
        elif rightSum:
            re += [[root.val] + x for x in rightSum]
        return re

面试题35:复杂链表的复制

  • 题目描述
    输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        # write code here
        def CloneNode(pHead):
            cur = pHead
            while cur:
                newNode = RandomListNode(cur.label)
                newNode.next = cur.next
                cur.next = newNode
                cur = newNode.next
            return pHead

        def CloneRandom(pHead):
            cur = pHead
            while cur:
                if cur.random:
                    cur.next.random = cur.random.next
                cur = cur.next.next
            return pHead

        def Split(pHead):
            cur_org = pHead
            cur_new = pHead.next
            pHead_new = pHead.next
            while cur_new.next:
                cur_org.next = cur_org.next.next
                cur_new.next = cur_new.next.next
                cur_org = cur_org.next
                cur_new = cur_new.next
            cur_org.next = None
            return pHead_new
        
        if not pHead:
            return None
        pHead = CloneNode(pHead)
        pHead = CloneRandom(pHead)
        pHead_new = Split(pHead)
        return pHead_new

面试题36:二叉搜索树与双向链表

  • 题目描述
    输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
# -*- 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 not pRootOfTree:
            return None
        if pRootOfTree.left:
            left_node = self.Convert(pRootOfTree.left)
            while left_node.right:
                left_node = left_node.right
            left_node.right = pRootOfTree
            pRootOfTree.left = left_node
        if pRootOfTree.right:
            right_node = self.Convert(pRootOfTree.right)
            right_node.left = pRootOfTree
            pRootOfTree.right = right_node
        while pRootOfTree.left:
            pRootOfTree = pRootOfTree.left
        return pRootOfTree

面试题37:序列化二叉树

  • 题目描述
    请实现两个函数,分别用来序列化和反序列化二叉树
    二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
    二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
	# shiyong前序遍历的思路
    def Serialize(self, root):
        # write code here
        if not root:
            return '$'
        s = str(root.val)
        left = self.Serialize(root.left)
        right = self.Serialize(root.right)
        return s + ',' + left + ',' + right
        
    def Deserialize(self, s):
        # write code here
        def DeserialStr(l):
            if l[0] == '$':
                return None, l[1:]
            root = TreeNode(int(l[0]))
            l = l[1:]
            left, l = DeserialStr(l)
            right, l = DeserialStr(l)
            root.left = left
            root.right = right
            return root, l
        l = s.split(',')
        root, s = DeserialStr(l)
        return root

面试题38:字符串的排列

  • 题目描述
    输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
# -*- coding:utf-8 -*-
class Solution:
    def Permutation(self, ss):
        # write code here
        if len(ss) == 1:
            return ss
        re = []
        for i in range(len(ss)):
            after = self.Permutation(ss[:i]+ss[i+1:])
            re += [ss[i] + x for x in after]
        res = []
        for r in re:
            if r not in res:
                res.append(r)
        res.sort(key=lambda x:ord(x[0]))
        return res

第五章

面试题39:数组中出现次数超过一半的数字

  • 题目描述
    数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为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
        hashmap = {}
        for num in numbers:
            if num in hashmap:
                hashmap[num] += 1
            else:
                hashmap[num] = 1
        half_length = 0.5 * len(numbers)
        for k,v in hashmap.items():
            if v > half_length:
                return k
        return 0

面试题40:最小的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
        if k > len(tinput):
            return []
        if k == len(tinput):
            return sorted(tinput)
        start, end = 0, len(tinput) - 1
        while True:
            tinput, pivot_idx = self.Partition(tinput, start, end, k)
            if pivot_idx == k:
                return sorted(tinput[0:k])
            elif pivot_idx > k:
                end = pivot_idx - 1
            else:
                start = pivot_idx + 1
    def Partition(self, nums, start, end, pivot_idx):
        # pivot置于最后
        nums[pivot_idx], nums[end] = nums[end], nums[pivot_idx]
        # 进行交换
        pivot = nums[end]
        store_idx = start
        for i in range(start, end):
            if nums[i] < pivot:
                nums[store_idx], nums[i] = nums[i], nums[store_idx]
                store_idx += 1
        # 把pivot换回来
        nums[store_idx], nums[end] = nums[end], nums[store_idx]
        return nums, store_idx

面试题41:数据流中的中位数

  • 题目描述
    如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
# -*- coding:utf-8 -*-
from heapq import *
class Solution:
    def __init__(self):
        self.heaps = [], []
        self.even = True
        
    def Insert(self, num):
        # write code here
        small, large = self.heaps
        heappush(large, -heappushpop(small, num))
        self.even = not self.even
        if self.even:	# if even,即已有数据是偶数个,且large比small多两个
            heappush(small, -heappop(large))
        
    def GetMedian(self,ss):
        # write code here
        small, large = self.heaps
        return 0.5 * (small[0]-large[0]) if self.even else -large[0]

面试题42:连续子数组的最大和

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

        for i in range(1, n):
            curr_sum = max(nums[i], curr_sum + nums[i])
            max_sum = max(max_sum, curr_sum)
            
        return max_sum

面试题43:1 ~ n整数中1出现的次数

  • 题目描述
    求出1-13的整数中1出现的次数,并算出100-1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        sum = 0
        for num in range(1, n+1):
            while(num):
                if num % 10 == 1:
                    sum += 1
                num = num // 10
        return sum

面试题44:数字序列中某一位的数字

  • 题目描述
    数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从0开始计数)是5,第13位是1,第19位是4,等等。请写一个函数求任意位对应的数字。
def getBitNumber(n):
    counts = [0]
    i = 1
    while True:
        count = 10 ** i - sum(counts)
        if n > count * i:
            n -= count * i
        else:
            break
        counts.append(count)
        i += 1
    num = n // i + sum(counts)
    bit = n % i
    return str(num)[bit]
print(getBitNumber(1001))

面试题45:把数组排成最小的数

  • 题目描述
    输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
# -*- coding:utf-8 -*-
class Solution:
    def PrintMinNumber(self, numbers):
        # write code here
        # 判断sa是否比sb小
        def IsSmaller(sa, sb):
            sab = sa + sb
            sba = sb + sa
            for i in range(len(sab)):
                if sab[i] < sba[i]:
                    return True
                elif sab[i] > sba[i]:
                    return False
            return True
        # 二分法
        def Partition(numbers, start, end):
            if start >= end:
                return numbers
            store_idx = start
            for i in range(start, end):
                if IsSmaller(numbers[i], numbers[end]):
                    numbers[store_idx], numbers[i] = numbers[i], numbers[store_idx]
                    store_idx += 1
            numbers[store_idx], numbers[end] = numbers[end], numbers[store_idx]
            numbers = Partition(numbers, start, store_idx - 1)
            numbers = Partition(numbers, store_idx + 1, end)
            return numbers

        numbers = [str(x) for x in numbers]
        numbers = Partition(numbers, 0, len(numbers)-1)
        re = ''
        for n in numbers:
            re += n
        return re

面试题46:把数字翻译成字符串

  • 题目描述
    给定一个数字,按照如下规则翻译成字符串:0翻译成“a”,1翻译成“b”…25翻译成“z”。一个数字有多种翻译可能,例如12258一共有5种,分别是bccfi,bwfi,bczi,mcfi,mzi。实现一个函数,用来计算一个数字有多少种不同的翻译方法。
def Possibilities(str):
    num = int(str)
    return 1 if num >= 10 and num <= 25 else 0

def Number2Str(num):
    num = str(num)
    if len(num) == 0:
        return 0
    if len(num) == 1:
        return 1
    trans = [0] * len(num)
    trans[0] = 1
    trans[1] = Possibilities(num[0:2]) + 1
    for i in range(2, len(num)):
        trans[i] = trans[i-2] * Possibilities(num[i-1:i+1]) + trans[i-1]
    return trans[-1]

Number2Str(12258)

面试题47:礼物的最大价值

  • 题目描述
    在一个m×n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向左或者向下移动一格直到到达棋盘的右下角。给定一个棋盘及其上面的礼物,请计算你最多能拿到多少价值的礼物?
def MaxValue(value):
    if not value:
        return 0
    m = len(value)
    n = len(value[0])
    value_sum = [[0] * n for x in range(m)] # 这里注意,不能使用[[0] * n] * m,这是因为创建的m个list指向相同地址
    for i in range(m):
        for j in range(n):
            up_sum = 0 if i == 0 else value_sum[i-1][j]
            left_sum = 0 if j == 0 else value_sum[i][j-1]
            value_sum[i][j] = max(up_sum, left_sum) + value[i][j]
    return value_sum[m-1][n-1]


value = [[1,10,3,8], [12,2,9,6], [5,7,4,11], [3,7,16,5]]
MaxValue(value)

面试题48:最长不含重复字符的子字符串

  • 题目描述
    请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符串中只包含’a’~'z’的字符。例如,在字符串"arabcacfr"中,最长的不含重复字符的子字符串就是"acfr",长度为4。
def MaxUnrepeat(str):
    if not str:
        return 0
    store26 = [-1] * 26
    store_unrepeat = [0] * len(str)
    for i in range(len(str)):
        if i == 0:
            store_unrepeat[i] = 1
        c = str[i]
        idx = ord(c) - ord('a')
        if i - store26[idx] > store_unrepeat[i - 1] or store26[idx] == -1:
            store_unrepeat[i] = store_unrepeat[i-1] + 1
        else:
            store_unrepeat[i] = i - store26[idx]
        store26[idx] = i
    return max(store_unrepeat)


MaxUnrepeat('arabcacfr')

面试题49:丑数

  • 题目描述
    把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
# -*- coding:utf-8 -*-
class Solution:
    def GetUglyNumber_Solution(self, index):
        def UpdateIdxM(idx, uglys, i, factor):
            while uglys[idx] * factor <= uglys[i - 1]:
                idx += 1
            return idx, uglys[idx] * factor
        
        if index == 0:
            return 0
        if index == 1:
            return 1
        uglys = [0] * index
        uglys[0] = 1
        idx2, idx3, idx5 = 0, 0, 0
        for i in range(1, index):
            idx2, m2 = UpdateIdxM(idx2, uglys, i, 2)
            idx3, m3 = UpdateIdxM(idx3, uglys, i, 3)
            idx5, m5 = UpdateIdxM(idx5, uglys, i, 5)
            uglys[i] = min([m2, m3, m5])
        return uglys[-1]

面试题50:第一个只出现一次的字符

  • 题目描述
    在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写)
# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        early2late = []
        hashmap = {}
        for i in range(len(s)):
            if s[i] not in early2late:
                early2late.append(s[i])
                hashmap[s[i]] = i + 1
            else:
                hashmap[s[i]] = -1
        for c in early2late:
            idx = hashmap[c]
            if idx > 0:
                return idx - 1
        return -1

面试题51:数组中的逆序对

  • 题目描述
    在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
# -*- coding:utf-8 -*-
class Solution:
    def InversePairs(self, data):
        # 时间复杂度nlogn,和归并法一样
        # 二分查找
        def Partition(numbers, num):
            left = 0
            right = len(numbers) - 1
            while left <= right:
                mid = int(0.5 * (left + right))
                if numbers[mid] > num:
                    right = mid-1
                else:
                    if mid == len(numbers) - 1 or numbers[mid+1] > num:
                        return mid
                    else:
                        left = mid + 1
            return -1
		# 维护一个有序的数组,每次插入一个数字,并找出已排序数组中,比它大的个数
        sorted_data = []
        sum = 0
        for num in data:
            idx = Partition(sorted_data, num)
            sum += len(sorted_data) - idx - 1
            sorted_data.insert(idx + 1, num)
        return sum % 1000000007

面试题52:两个链表的第一个公共节点

  • 题目描述
    输入两个链表,找出它们的第一个公共结点。
# -*- 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
        if pHead1 == pHead2:
            return pHead1
        stack1 = []
        stack2 = []
        while pHead1:
            stack1.append(pHead1)
            pHead1 = pHead1.next
        while pHead2:
            stack2.append(pHead2)
            pHead2 = pHead2.next
        while stack1 and stack2:
            cur1 = stack1.pop()
            cur2 = stack2.pop()
            if cur1 == cur2:
                continue
            else:
                return cur1.next
        if not stack1 and not stack2:
            return None
        if not stack1:
            return stack2[-1].next
        if not stack2:
            return stack1[-1].next

第六章

面试题53:在排序数组中查找数字

  • 题目描述
    统计一个数字在排序数组中出现的次数。
# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        idx_start = self.SearchFirst(data, 0, len(data)-1, k)
        if idx_start == -1:
            return 0
        idx_end = self.SearchLast(data, 0, len(data)-1, k)
        return idx_end - idx_start + 1
        
        
    # 查找第一个等于target的元素
    # 找到 —— 返回索引,找不到 —— 返回-1
    def SearchFirst(self, array, left, right, target):
        while left <= right:
            mid = left + int(0.5 * (right - left))
            if array[mid] < target:
                left = mid + 1
            elif array[mid] > target:
                right = mid - 1
            else:
                if mid == left or array[mid-1] != target:
                    return mid
                else:
                    right = mid - 1
        return -1


    # 查找最后一个等于target的元素
    # 找到 —— 返回索引,找不到 —— 返回-1
    def SearchLast(self, array, left, right, target):
        while left <= right:
            mid = left + int(0.5 * (right - left))
            if array[mid] < target:
                left = mid + 1
            elif array[mid] > target:
                right = mid - 1
            else:
                if mid == right or array[mid+1] != target:
                    return mid
                else:
                    left = mid + 1
        return -1

面试题54:二叉搜索树的第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
        def GetSorted(pRoot):
            if not pRoot:
                return []
            left = GetSorted(pRoot.left)
            right = GetSorted(pRoot.right)
            return left + [pRoot] + right
        
        if k <= 0:
            return None
        sorted_tree = GetSorted(pRoot)
        if k > len(sorted_tree):
            return None
        return sorted_tree[k-1]

面试题55:二叉树的深度

  • 题目描述
    输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
# -*- 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
        return max(self.TreeDepth(pRoot.left), self.TreeDepth(pRoot.right)) + 1

面试题56:数组中数字出现的次数

  • 题目描述
    一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
# -*- coding:utf-8 -*-
class Solution:
    def FindNumsAppearOnce(self, array):
        if not array:
            return []
        # 对array中的数字进行异或运算
        tmp = 0
        for i in array:
            tmp ^= i
        # 获取tmp中最低位1的位置
        idx = 0
        while (tmp & 1) == 0:
            tmp >>= 1
            idx += 1
        # 分成两组计算异或
        a = b = 0
        for i in array:
            if (i >> idx) & 1:
                a ^= i
            else:
                b ^= i
        return [a, b]

面试题57:和为s的数字

  • 题目描述
    输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        i = 0
        j = len(array) - 1
        n_min = -1
        n_max = -1
        product = 0
        while i < j:
            s = array[i] + array[j]
            if s < tsum:
                i += 1
            elif s > tsum:
                j -= 1
            else:
                if array[i] * array[j] < product or n_min == -1:
                    n_min = array[i]
                    n_max = array[j]
                    product = n_min * n_max
                i += 1
        if n_max == -1:
            return []
        else:
            return n_min, n_max

面试题58:翻转字符串

  • 题目描述
    牛客最近来了一个新员工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
        word_list = s.split(' ')
        re = ''
        while word_list:
            re += ' ' + word_list.pop()
        return re[1:]

面试题59:队列的最大值

  • 题目描述
    给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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 size == 0:
            return []
        queue,res,i = [],[],0
        for i in range(len(num)):
            if len(queue)>0 and i-size+1 > queue[0]: #若最大值queue[0]位置过期 则弹出 
                queue.pop(0)
            while len(queue)>0 and num[queue[-1]]<num[i]: #弹出所有比num[i]小的数字
                queue.pop()
            queue.append(i)
            if i >= size-1:	# 从第size个位置,开始输出
                res.append(num[queue[0]])
        return res

面试题60:n个骰子的点数

  • 题目描述
    题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率。
n = 2
s = 2
for i in range(n):
    store = [0] * 6 * (i+1)
    if i == 0:
        store = [1] * 6
        store_pre = store
    else:
        for j in range(i, 6*(i+1)):
            store[j] = sum(store_pre[:j]) if j < 6 else sum(store_pre[j-6:j])
        store_pre = store
    # print(store)
print(store[s-1]/6**n)

面试题61:扑克牌中的顺子

  • 题目描述
    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。
# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        # write code here
        if len(numbers) != 5:
            return False
        numbers.sort()
        count0 = 0
        for i in range(len(numbers)):
            if numbers[i] == 0:
                count0 += 1
            else:
                start = i
                break
        if numbers[start] < 1 or numbers[-1] > 13:
            return False
        for i in range(start, len(numbers) - 1):    # 判断有无重复的牌
            if numbers[i] == numbers[i+1]:
                return False
        if count0 >= (numbers[-1] - numbers[start] - 1) - (len(numbers) - start - 2):
            return True
        else:
            return False

面试题62:圆圈中最后剩下的数字

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

面试题63:股票的最大利润

  • 题目描述
    给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
    如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        low = 0
        profit = 0
        for i, price in enumerate(prices):
            if price < prices[low]:
                low = i
            elif price > prices[low]:
                profit = max(profit, price - prices[low])
            else:
                continue
        return profit

面试题64:求1+2+……+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
        # python的a and b, a == False 则取a, 否则取b
        return n and (n + self.Sum_Solution(n - 1))

面试题65:不用加减乘除做加法

  • 题目描述
    写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
  • 举例
    当num1 = -1, num2 = -5时
    剑指offer的python解答合集(更新完毕)_第1张图片
# -*- coding:utf-8 -*-
class Solution:
    def Add(self, num1, num2):
        # write code here
        # 由于题目要求不能使用四则运算,那么就需要考虑使用位运算
        # 两个数相加可以看成两个数的每个位先相加,但不进位,然后在加上进位的数值
        # 如12+8可以看成1+0=1 2+8=0,由于2+8有进位,所以结果就是10+10=20
        # 二进制中可以表示为1000+1100 先每个位置相加不进位,
        # 则0+0=0 0+1=1 1+0=1 1+1=0这个就是按位异或运算
        # 对于1+1出现进位,我们可以使用按位与运算然后在将结果左移一位
        # 最后将上面两步的结果相加,相加的时候依然要考虑进位的情况,直到不产生进位
        # 注意python没有无符号右移操作,所以需要越界检查
        # 按位与运算:相同位的两个数字都为1,则为1;若有一个不为1,则为0。
        # 按位异或运算:相同位不同则为1,相同则为0。
        while num2:
            result = (num1 ^ num2) & 0xffffffff
            carry = ((num1 & num2) << 1) & 0xffffffff
            num1 = result
            num2 = carry
        if num1 <= 0x7fffffff:
            result = num1
        else:
            result = ~(num1^0xffffffff)
        return result

面试题66:构建乘积数组

  • 题目描述
    给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1].不能使用除法。
a = [4,6,2,4,8,3,4]
length = len(a)
before, after = [1] * length, [1] * length
for i in range(1,length):
    before[i] = before[i-1] * a[i-1]
    after[length-i-1] = after[length-i] * a[length-i]
re = [before[i]*after[i] for i in range(length)]
print(re)

你可能感兴趣的:(杂七杂八的代码,基础算法)