python版剑指offer(复习用)

本文章用来记录自己第二次刷题遇到的各种问题

面试题03. 数组中重复的数字

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

解题思路:一开始想到哈希表。然后看视频发现可以原地交换,具体思路为:
遍历列表,如果nums[i] 不在 i位置上,判断nums[i]是否等于nums[nums[i]],如果相等,就返回,不相等, 把nums[i] 放到 i位置上,继续找下一个。

class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        for i in range(len(nums)):
            if nums[i] != i:
                if nums[i] == nums[nums[i]]:
                    return nums[i]
                else:
                    nums[nums[i]],nums[i] = nums[i],nums[nums[i]]
                    # nums[i],nums[nums[i]] = nums[nums[i]],nums[i]

注意:Python 中, a, b = c, d 操作的原理是先暂存元组 (c, d) ,然后 “按顺序” 赋值给 a 和 b 。因此,若写为 nums[i], nums[nums[i]] = nums[nums[i]], nums[i] ,则 nums[i] 先被赋值,之后 nums[nums[i]] 指向的元素则会出错。

面试题04. 二维数组中的查找

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

解题思路: 第一种方法:遍历,时间复杂度 O(n)
      第二种,和右上角的比较,比他大就往下走,比他小就往左走

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        if matrix == []:return False        
        row = len(matrix)
        cloumn = len(matrix[0])
        if row == 1 and cloumn == 1:
            return True if matrix[0][0] == target else False
        
        i = 0
        j = cloumn - 1
        while 0 <= i < row and 0 <= j < cloumn:
            if matrix[i][j] == target:
                return True
            elif matrix[i][j] > target:
                j -= 1
            else:
                i += 1
        return False

面试题05. 替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

class Solution:
    def replaceSpace(self, s: str) -> str:
        b = ''
        for i in s:
            if i == ' ':
                b = b + '%20'
            else:
                b = b + i
        return b

面试题06. 从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        #第一种方法,递归,第二种,辅助栈
        # return self.reversePrint(head.next) + [head.val] if head else []
        stack = []
        while head:
            stack.append(head.val)
            head = head.next
        res = []
        while stack:
            res.append(stack.pop())
        return res

面试题07. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not preorder or not inorder:return None
        root = TreeNode(preorder[0])
        index = inorder.index(preorder[0])
        root.left = self.buildTree(preorder[1:index+1],inorder[:index])
        root.right = self.buildTree(preorder[index+1:],inorder[index+1:])
        return root

面试题09. 用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

解题思路:没啥好说的,就是干!

class CQueue:

    def __init__(self):
        self.input_stack = []
        self.output_stack = []

    def appendTail(self, value: int) -> None:
        self.input_stack.append(value)

    def deleteHead(self) -> int:
        if self.output_stack == []:
            while self.input_stack:
                self.output_stack.append(self.input_stack.pop())
        if self.output_stack:
            return self.output_stack.pop()
        else:
            return -1

面试题10- I. 斐波那契数列

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:

F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

class Solution:
    def fib(self, n: int) -> int:
        if n == 0:return 0
        if n == 1:return 1
        # 这种方法TLE,因为有太多重复计算
        # return (self.fib(n-1) + self.fib(n-2))%1000000007
        
        a = 0
        b = 1
        for i in range(2,n+1):
            c = a + b
            a = b
            b = c
        return c%1000000007

面试题10- II. 青蛙跳台阶问题

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

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

解题思路:DP动态规划, 可继续优化

class Solution:
    def numWays(self, n: int) -> int:
        if n == 0:return 1
        if n == 1:return 1
        if n == 2:return 2

        dp = [0 for i in range(n+1)]
        dp[0] = 1
        dp[1] = 1
        dp[2] = 2

        for i in range(3,n+1):
            dp[i] = dp[i-1] + dp[i-2]
        return dp[-1]%1000000007

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

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

解题思路:二分法的变体,难点为考虑 left 和 mid 相等的情况时, 是左加1还是右减1

class Solution:
    def minArray(self, numbers: List[int]) -> int:
        # 二分查找的变体
        if not numbers:return None
        left = 0
        right = len(numbers) - 1

        if numbers[left] < numbers[right]:
            return numbers[0]

        while left < right:
            mid = (left + right) //2
            if numbers[left] < numbers[mid]:
                left = mid + 1
            elif numbers[left] > numbers[mid]:
                right = mid
            else:
                left += 1
        return numbers[left]

面试题12. 矩阵中的路径

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。

[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]

但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。

解题思路: 深度优先算法,走过的标记为1,没走的标记为0

第一遍答案
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        n = len(board[0])
        m = len(board)

        if m == 0:
            return False

        mark = [[0 for _ in range(n)] for _ in range(m)]
        for i in range(m):
            for j in range(n):
                if mark[i][j] == 0 and board[i][j] == word[0]:
                    mark[i][j] = 1
                    if self.backtrack(i,j,mark,board,word[1:]) == True:
                        return True
                    else:
                        mark[i][j] = 0
        return False

    directions = [(0,1),(0,-1),(1,0),(-1,0)]
    def backtrack(self,i,j,mark,board,word):
        if len(word) == 0:
            return True
        n = len(board[0])
        m = len(board)   
        for direction in self.directions:
            cur_i = i + direction[0]
            cur_j = j + direction[1]
            if 0 <= cur_i < m and 0 <= cur_j < n and board[cur_i][cur_j] == word[0]:
                if mark[cur_i][cur_j] == 0:
                    mark[cur_i][cur_j] = 1
                    if self.backtrack(cur_i,cur_j,mark,board,word[1:]) == True:
                        return True
                    else:
                        mark[cur_i][cur_j] = 0
        return False

第二遍答案
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        def dfs(i,j,k):
            if not 0 <= i < len(board) or not 0 <= j < len(board[0]) or board[i][j] != word[k]:
                return False
            temp,board[i][j] = board[i][j], '/'
            res = dfs(i-1,j,k+1) or dfs(i+1,j,k+1) or dfs(i,j-1,k+1) or dfs(i,j+1,k+1)
            board[i][j] = temp
            return res
        
        for i in range(len(board)):
            for j in range(len(board[0])):
                if dfs(i,j,0):return True
        return False



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

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

第一遍答案
class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        # bfs
        directions = [(0,1),(0,-1),(1,0),(-1,0)]
        count = 1
        queue = [(0,0)]
        res = [(0,0)]

        while queue:
            cur = queue.pop(0)
            for x,y in directions:
                summ = 0
                cur_x = cur[0] + x 
                cur_y = cur[1] + y 
                if (cur_x,cur_y) in res:
                    continue
                res.append((cur_x,cur_y))
                if 0 <= cur_x < m and 0 <= cur_y < n:
                    while cur_x > 0:
                        summ += cur_x % 10
                        cur_x //= 10
                    while cur_y > 0:
                        summ += cur_y % 10
                        cur_y //= 10
                if 0 < summ <= k:
                    queue.append((cur[0] + x ,cur[1] + y))
                    count += 1
        return count
第二遍答案 dfs
class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        # dfs
        def summ(x,y):
            summer = 0
            while x > 0:
                summer += x % 10
                x //= 10
            while y > 0:
                summer += y % 10
                y //= 10
            return summer
        
        def dfs(i,j):
            if not 0 <= i < m or not 0 <= j < n or (i,j) in marked or summ(i,j) > k:
                return 
            else:
                marked.add((i,j))
                dfs(i+1,j)
                dfs(i,j+1)

        marked = set()
        dfs(0,0)
        return len(marked)



面试题14- I. 剪绳子

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
解题思路: 这个最小的只能分成2或3,求最值,果断动态规划。

class Solution:
    def cuttingRope(self, n: int) -> int:
        dp = [0 for i in range(n + 1)]
        dp[1] = 1
        dp[2] = 1

        for i in range(3,n+1):
            for j in range(i):
                # max中的dp[i] 为 上一次循环中的最大值
                dp[i] = max(dp[j]*(i-j),dp[i-j]*j,(i-j)*j,dp[i])
        return dp[-1]

面试题14- II. 剪绳子 II

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

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

class Solution:
    def cuttingRope(self, n: int) -> int:
        dp = [0 for i in range(n+1)]
        dp[1] = dp[2] = 1
        for i in range(3,n+1):
            for j in range(i):
                dp[i] = max((i-j)*j,dp[i-j]*j,dp[j]*(i-j),dp[i])
        return dp[-1] % 1000000007

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

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

解题思路:第一遍:每次右移一位。第二遍,和n-1作比较,每次可以去掉最后一个1.

第一遍
class Solution:
    def hammingWeight(self, n: int) -> int:
        res = 0
        while n:
            res += n & 1
            n >>= 1
        return res
第二遍
class Solution:
    def hammingWeight(self, n: int) -> int:
        count = 0
        if n < 0:
            n = n&0xffffffff
        while n:
            n = n&(n-1)
            count += 1
        return count

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

实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。

解题思路: 如果一个一个乘,会超时。因此考虑二分法。n为奇数就和res相乘,为偶数就和自己相乘。然后n在整除2

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if x == 0:
            return 0
        if n < 0:
            x = 1/x
            n = n*-1
        res = 1
        while n:
            if n%2 == 1:
                res *= x
            x *= x
            n //= 2
        return res

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

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
解题思路: 此题我的解法不正确。并没有充分理解出题人的意图

class Solution:
    def printNumbers(self, n: int) -> List[int]:
        return [i for i in range(1,10**n)]

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

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。

注意:此题对比原题有改动
解题思路: 最简单的双指针,注意虚拟节点

class Solution:
    def deleteNode(self, head: ListNode, val: int) -> ListNode:
        # 双指针一前一后
        if not head:return []
        dummy = ListNode(None)
        dummy.next = head
        pre = dummy
        cur = head
        while cur:
            if cur.val == val:
                pre.next = cur.next
            pre = pre.next
            cur = cur.next
        return dummy.next

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

请实现一个函数用来匹配包含’. ‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。
解题思路: 通过翻阅题解,发现可用二维动态规划,然而还用一种递归解法,遗憾的是笔者并未做过多的了解。

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        if not p:return not s
        if not s and len(p) == 1:return False

        dp = [[False for i in range(len(s)+1)] for j in range(len(p)+1)]
        dp[0][0] = True
        dp[1][0] = False

        for i in range(2,len(p)+1):
            if p[i-1] == '*':
                dp[i][0] = dp[i-2][0]
        
        for i in range(1,len(s)+1):
            dp[0][i] = False

        for i in range(1,len(p)+1):
            for j in range(1,len(s)+1):
                if p[i-1] == s[j-1]:
                    dp[i][j] = dp[i-1][j-1]
                elif p[i-1] == '.':
                    dp[i][j] = dp[i-1][j-1]
                elif p[i-1] == '*':
                    if p[i-2] == s[j-1]:
                        dp[i][j] = dp[i-2][j] or dp[i][j-1]
                    elif p[i-2] == '.':
                        dp[i][j] = dp[i-2][j] or dp[i][j-1]
                    else:
                        dp[i][j] = dp[i-2][j]
                else:
                    dp[i][j] = False
        # print(dp)
        return dp[-1][-1]

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

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、“5e2”、"-123"、“3.1416”、“0123"都表示数值,但"12e”、“1a3.14”、“1.2.3”、“±5”、"-1E-16"及"12e+5.4"都不是。

解题思路: 注意几个限制条件,重点为将几个值设置为False

class Solution:
    def isNumber(self, s: str) -> bool:
        # 1.加减只能在开始或者e后面第一位
        # 2.e 只能出现一次,且后面必须跟数字
        # 3.e后面不能有小数点
        # 4.e前面不能没有数字
        # 5.空格只能在两端

        s = s.strip()
        nums = [str(i) for i in range(10)]
        n = len(s)

        e_showup = False
        e_dot = False
        dot_showup = False
        num_showup = False
        num_after_e = False

        for i in range(n):
            c = s[i]
            if c in nums:
                num_showup = True
                num_after_e = True
            elif c in ('+','-'):
                if i > 0 and s[i-1] != 'e':
                    return False

            elif c == '.':
                if e_showup or dot_showup:
                    return False
                dot_showup = True
            elif c == 'e':
                if e_showup or not num_showup:
                    return False
                e_showup = True
                num_showup = False
            else:
                return False
        return num_showup and num_after_e

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

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
解题思路:左右两个指针,一趟遍历。

class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        left = 0
        right = len(nums) - 1
        while left < right :
            while nums[left] % 2 == 1 and left < right:
                left += 1
            while nums[right] % 2 == 0 and left < right:
                right -= 1
            temp = nums[left]
            nums[left] = nums[right]
            nums[right] = temp
            left += 1
            right -= 1
        return nums

面试题22. 链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。
解题思路:快慢指针,加个虚拟头结点。

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        #快慢指针,快指针前进k步,快指针指向最后一个时,慢指针的下一个就是倒数第k个节点
        if not head:
            return None
        dummy = ListNode(None)
        dummy.next = head
        fast,slow = dummy,dummy
        count = 0
        while count <= k:
            count += 1
            fast = fast.next
            
        while fast:
            fast = fast.next
            slow = slow.next
        return slow.next

面试题24. 反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
解题思路:双指针掉头

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head:
            return None
        # 双指针
        pre = None
        cur = head
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre

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

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if not l1 and not l2:
            return None
        dummy = ListNode(-1)
        p = dummy
        while l1 and l2:
            if l1.val < l2.val:
                p.next = l1
                p = p.next
                l1 = l1.next
            else:
                p.next = l2
                p = p.next
                l2 = l2.next
        while l1:
            p.next = l1
            p = p.next
            l1 = l1.next
            
        while l2:
            p.next = l2
            p = p.next
            l2 = l2.next
        return dummy.next

面试题26. 树的子结构

输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)

B是A的子结构, 即 A中有出现和B相同的结构和节点值。
解题思路:先定义一个匹配方法,然后分别将当前节点、当前节点的两个子节点与B进行比较,只要有一个为True即可。

class Solution:
    def match(self,A,B):
        if not B:return True
        if not A:return False
        if A.val != B.val:return False
        return self.match(A.left,B.left) and self.match(A.right,B.right)

    def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
        if A and B:
            return self.isSubStructure(A.left,B) or self.isSubStructure(A.right,B) or self.match(A,B)
        else:
            return False

面试题27. 二叉树的镜像(不熟练)

请完成一个函数,输入一个二叉树,该函数输出它的镜像。
解题思路:最主要为hlper函数的创建,先将两个子节点互换位置,再递归。

class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        if not root:return root
        def helper(root):
            if not root:return
            root.left,root.right = root.right,root.left
            helper(root.left)
            helper(root.right)
        helper(root)
        return root

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

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
解题思路:一圈一圈循环即可,值得注意的是,不能在最后再执行上下左右缩小一圈,如果这样做,即使找到最后一个点,也会循环完本次。应当在上方遍历完后,立即加一,然后判断上是否大于下。

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix:return []
        left = 0
        right = len(matrix[0]) - 1
        up = 0
        down = len(matrix) - 1
        ans = []
        while left <= right and up <= down :
            # 每次循环一圈
            for i in range(left,right+1):
                ans.append(matrix[up][i])
                # print(matrix[up][i])
            up += 1
            if  up > down:break 
            for i in range(up,down+1):
                ans.append(matrix[i][right])
                # print(matrix[i][right])
            right -= 1
            if left > right:break
            for i in range(right,left-1,-1):
                ans.append(matrix[down][i])
                print(right,left-1)
                print(matrix[down][i])
            down -= 1
            if up > down:break
            for i in range(down,up-1,-1):
                ans.append(matrix[i][left])
                # print(matrix[i][left])
            left += 1
            # left += 1
            # right -= 1
            # up += 1
            # down -= 1
            # print(ans)
            # print(left,right,up,down)
        return ans

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

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

解题思路:太简单,奥利给!

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        self.min_stack = []

    def push(self, x: int) -> None:
        self.stack.append(x)
        if len(self.stack) == 1:
            self.min_stack.append(x)
        else:
            if x < self.min_stack[-1]:
                self.min_stack.append(x)
            else:
                self.min_stack.append(self.min_stack[-1])
        # print(self.stack,self.min_stack)        
    def pop(self) -> None:
        self.min_stack.pop()
        return self.stack.pop()  

    def top(self) -> int:
        return self.stack[-1]

    def min(self) -> int:
        return self.min_stack[-1]

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

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
解题思路:模仿栈的操作。

class Solution:
    def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        stack = []
        i = 0
        for num in pushed:
            stack.append(num)
            while stack and stack[-1] == popped[i]:
                i += 1
                stack.pop()
        return not stack

面试题32 - I. 从上到下打印二叉树

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

class Solution:
    def levelOrder(self, root: TreeNode) -> List[int]:
        if not root:return []
        #层次遍历
        cur_layer = [root]
        ans = []
        while cur_layer:
            next_layer = []
            for cur in cur_layer:
                ans.append(cur.val)
                if cur.left:
                    next_layer.append(cur.left)
                if cur.right:
                    next_layer.append(cur.right)
            cur_layer = next_layer
        return ans

面试题32 - II. 从上到下打印二叉树 II

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root:
            return []
        ans = []
        cur_level = [root]
        while cur_level:
            cur_val = []
            next_level = []
            for cur in cur_level:
                cur_val.append(cur.val)
                if cur.left:
                    next_level.append(cur.left)
                if cur.right:
                    next_level.append(cur.right)
            ans.append(cur_val)
            cur_level = next_level
        return ans

面试题32 - III. 从上到下打印二叉树 III

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

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root:return []
        ans = []
        cur_level = [root]
        count = 1
        while cur_level:
            cur_val = []
            next_level = []
            for cur in cur_level:
                if count % 2 != 0:
                    cur_val.append(cur.val)
                else:
                    cur_val.insert(0,cur.val)
                if cur.left:
                    next_level.append(cur.left)
                if cur.right:
                    next_level.append(cur.right)
            count += 1
            ans.append(cur_val)
            cur_level = next_level
        return ans

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

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
解题思路:找到第一个大于n的值,如果后面有小于n的值,判定为假。

class Solution:
    def verifyPostorder(self, postorder: List[int]) -> bool:
        #递归解决
        if not postorder:return True
        n = postorder[-1]
        index = 0
        for i in range(len(postorder)-1):
            if postorder[i] < n:
                index += 1
            else:
                break
        for i in range(index+1,len(postorder)):
            if postorder[i] < n:
                return False
        return self.verifyPostorder(postorder[:index]) and self.verifyPostorder(postorder[index:len(postorder)-1])

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

输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
        ans = []
        path = []
        def dfs(node,target):
            if not node:return
            target -= node.val
            path.append(node.val)
            if target == 0 and not node.left and not node.right:
                ans.append(list(path))
            dfs(node.left,target)
            dfs(node.right,target)
            path.pop()
        dfs(root,sum)
        return ans

面试题35. 复杂链表的复制(不熟,有更好的解法)

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
解题思路:建一个哈希表,如果没有就放进去,如果有就取出来。此题有更优秀的解法,建议反复做。

bfs
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        visited = {}
        def bfs(node):
            if not node:return
            copy = Node(node.val,None,None )
            queue = []
            queue.append(node)
            visited[node] =copy
            while queue:
                temp = queue.pop()
                if temp.next and temp.next not in visited:
                    visited[temp.next] = Node(temp.next.val, None ,None )
                    queue.append(temp.next)
                if temp.random and temp.random not in visited:
                    visited[temp.random] = Node(temp.random.val ,None ,None )
                    queue.append(temp.random)
                visited[temp].next = visited.get(temp.next)
                visited[temp].random = visited.get(temp.random)
            return copy
        return bfs(head)
dfs
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        visited = {}
        def dfs(node):
            if not node:return
            if node in visited:return visited[node]
            copy = Node(node.val,None,None)
            visited[node] = copy
            copy.next = bfs(node.next)
            copy.random = bfs(node.random)
            return copy
        return dfs(head)

面试题36. 二叉搜索树与双向链表(不熟)

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
解题思路:深度优先遍历,先找到最左边的点,成为头结点。

用栈
class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':
        if not root:return 
        stack = []
        head = None
        last = None
        node = root
        while node or stack:
            while node:
                stack.append(node)
                node = node.left
            node = stack.pop()
            if not head:
                head = node
            else:
                node.left = last
                last.right = node
            last = node
            node = node.right
        head.left = last
        last.right = head
        return head
递归
class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':
        def dfs(cur):
            if not cur:return
            dfs(cur.left)
            if self.pre:
                self.pre.right = cur
                cur.left = self.pre
            else:
                self.head = cur
            self.pre = cur
            dfs(cur.right)

        if not root:return 
        self.pre = None
        dfs(root)
        self.head.left = self.pre
        self.pre.right = self.head
        return self.head
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值