剑指offer: python全解. 持续ing...

目录

03. 数组中重复的数字: hash表、数组遍历

04. 二维数组中的查找:二分查找的思路

05. 替换空格:注意“”.join的用法

06. 从尾到头打印链表:python list逆序输出、栈实现

07. 重建二叉树:树的遍历、递归和栈

用栈进行迭代(*):

09. 用两个栈实现队列:辅助栈

10-I. 斐波那契数列:简单的递归、简单的动态规划

动态规划(简单):

10-II. 青蛙跳台阶问题:

11. 旋转数组的最小数字:(二分法**)

12. 矩阵中的路径:dfs(*)

13. 机器人的运动范围:Bfs(*)

14-I. 剪绳子:(数学推导*、贪心*)

14-II. 剪绳子2:(在剪绳子1的基础上多了大数求余(循环求余,快速幂求余)**)

15. 二进制中1的个数:(位运算)

16. 数值的整数次方:(快速幂**)

17. 打印从1到最大的n位数:(将该题推广到大数范围*)


03. 数组中重复的数字: hash表、数组遍历

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

示例:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3 

PS: 2 <= n <= 100000

一刷:

遍历数组再用hash表存放:

class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        numberset = dict()
        for i in nums:
            if i in numberset:
                return i
            else:
                numberset[i] = 1
        return -1

04. 二维数组中的查找:二分查找的思路

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

示例:

现有矩阵 matrix 如下:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。

给定 target = 20,返回 false。

PS:

限制:0 <= n <= 1000,0 <= m <= 1000

一刷:

从左到右递增,从上到下递增, 那么从最右上角开始查找就像是一棵二分查找树

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

时间复杂度O(n+m)

05. 替换空格:注意“”.join的用法

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

示例:

输入:s = "We are happy."
输出:"We%20are%20happy."

PS:0 <= s 的长度 <= 10000

class Solution:
    def replaceSpace(self, s: str) -> str:
        res = []
        for c in s:
            if c == ' ':
                res.append("%20")
            else:
                res.append(c)
        return "".join(res)

06. 从尾到头打印链表:python list逆序输出、栈实现

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

示例:

输入:head = [1,3,2]
输出:[2,3,1]

PS: 0<= 链表长度 <= 10000

一刷:python list可实现逆序输出

# class ListNode:
#     def __init__(self, x):
#        self.val = x
#        self.next = None

class solution:
    def reversePrint(self, head:ListNode) -> List[int]:
    res = []
    while(head != None):
        res.append(head.val)
        head = head.next
    return res[::-1]

当然也可以用栈来实现:

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class stack(object):
    def __init__(self):
        self.top=None # 初始栈顶为空
    
    def push(self, n):
        n = ListNode(n)
        if self.top == None:
            self.top = n
        else:
            n.next = self.top
            self.top = n
    
    def pop(self, n):
        if self.top == None:
            print("stack is empty")
            return None
        else:
            temp = self.top.val
            self.top = self.top.next
            return temp
    
    def allquit(self): # 打印栈,完成后栈为空
        alist = []
        while self.top != None:
            temp = self.top.val
            self.top = self.top.next
            alist.append(temp)
            print(alist)

class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        res = []
        s = stack()
        while(head != None):
            s.push(head.val)
            # res.append(head.val)
            head = head.next
        while s.top != None:
            temp = s.top.val
            s.top = s.top.next
            res.append(temp)
        return res

07. 重建二叉树:树的遍历、递归和栈

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

样例:

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

一刷:

递归:

# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        i = 0
        n = len(inorder)
        if preorder == []:
            return None
        tree = TreeNode(preorder[0])
        while(i < n):
            if inorder[i] == preorder[0]:
                break
            i += 1
        tree.left = self.buildTree(preorder[1:1+i],inorder[0:i])
        tree.right = self.buildTree(preorder[i+1::],inorder[i+1::])
        return tree

用栈进行迭代(*):

class Solution:
    def buildTree(self, preorder: List[int], inorder:List[int]) -> TreeNode:
        if len(preorder) == 0:
            return None
        stack = []
        i = 0
        root = TreeNode(preorder[0])
        stack.append(root)
        for p in range(1, len(preorder)):
            node = stack[-1]
            if node.val != inorder[i]:
                node.left = TreeNode(preorder[p])
                stack.append(node.left)
            else:
                while((len(stack) != 0) and (stack[-1].val == inorder[i])):
                    node = stack.pop()
                    i += 1
                node.right = TreeNode(preorder[p])
                stack.append(node.right)
        return root

09. 用两个栈实现队列:辅助栈

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

示例:

输入:
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
输出:[null,null,3,-1]

一刷:栈的作用是先入后出,而队列是先入先出,那么用栈实现队列取数顺序,意味着需要将栈内的元素进行反序排序,那么就可以利用辅助栈来进行一个反序操作,这样做插入的时间复杂度是O(n^2),空间复杂度O(n)

class CQueue:

    def __init__(self):
        # 存放队列元素
        self.stack1 = []
        # 辅助栈
        self.stack2 = []

    def appendTail(self, value: int) -> None:
        if (self.stack1 == []) and (self.stack2 == []):
            self.stack1.append(value)
        else:
            # 插入新数之前先将栈1(已经按照队列顺序排好)逆序存放到辅助栈中
            while(self.stack1 != []):
                self.stack2.append(self.stack1.pop())
            # 栈1放入存放元素
            self.stack1.append(value)
            # 辅助栈元素反序进入栈1,则栈1的输出顺序就跟队列一致了
            while(self.stack2 != []):
                self.stack1.append(self.stack2.pop())


    def deleteHead(self) -> int:
        if self.stack1 == []:
            return -1
        else:
            return self.stack1.pop()

最佳解法是用一个栈来实现插入,另一个栈来实现删除,当需要删除时对辅助栈进行操作,如果为空则从stack1里弹出所有元素。否则从辅助栈弹出元素,如果都为空就返回-1,这样每个元素都只会移动一次,时间复杂度为O(1),空间复杂度为O(n)

class CQueue:

    def __init__(self):
        self.stack1 = []
        self.stack2 = []

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


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

10-I. 斐波那契数列:简单的递归、简单的动态规划

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

F(0) = 0,   F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1

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

一刷:递归, 当然递归时间复杂度为O(2^n)(二叉树的节点数),空间复杂度O(n),时间会炸:

class Solution:
    def fib(self, n: int) -> int:
        if n == 1:
            return 1
        elif n == 0:
            return 0
        else:
            return (self.fib(n-1) + self.fib(n-2)) % (1000000007)

动态规划(简单):

class Solution:
    def fib(self, n: int) -> int:
        if n == 1:
            return 1
        if n == 0:
            return 0
        dp = [0 for x in range(0,n+1)]
        dp[0] = 0
        dp[1] = 1
        for i in range(2,n+1):
            dp[i] = dp[i - 1] + dp[i - 2]
        return dp[n] % (1000000007)

这里踩了一个坑,如果1000000007用1e9+7代替的话会出现精度问题,单独列出来有待思考。

当然上面的动态规划时间复杂度和空间复杂度都是O(n),其实还能在空间上进行优化,因为最后的结果只与之前的两个状态有关

由于 Python 中整形数字的大小限制 取决计算机的内存 (可理解为无限大),因此可不考虑大数越界问题。

如果用java这类严格定义存储类型的语言则要考虑内存溢出问题,就要在循环中添加求余操作

class Solution:
    def fib(self, n: int) -> int:
        if n == 1:
            return 1
        if n == 0:
            return 0
        sum_ = 0
        dp1 = 0
        dp2 = 1
        for i in range(2,n+1):
            sum_ = dp1 + dp2
            dp1 = dp2
            dp2 = sum_
        return sum_ % (1000000007)

最简洁的写法,其实实际运行效率还不如上面把0和1单独放一边,sum作为返回可读性也更好:

class Solution:
    def fib(self, n: int) -> int:
        dp1 = 0
        dp2 = 1
        for i in range(n):
            dp1, dp2 = dp1 + dp2, dp1
        return dp1 % (1000000007)

10-II. 青蛙跳台阶问题:

题目:

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

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

示例 :

输入:n = 2
输出:2
输入:n = 7
输出:21
输入:n = 0
输出:1

一刷:

动态规划的思想,青蛙每次可以跳1步,也可以跳两步,那么青蛙最后一步只能跳一步或者两步,则令f(n)表示n级台阶的跳法,有:f(n) = f(n-1) + f(n-2), 则变成了求解斐波那契数列(上一个问题), 注意初项f(0) = 1

class Solution:
    def numWays(self, n: int) -> int:
        if n == 0:
            return 1
        if n == 1:
            return 1
        dp1 = 1
        dp2 = 1
        for i in range(2, n+1):
            dp2, dp1 = dp2 + dp1, dp2
        return dp2%1000000007

 

11. 旋转数组的最小数字:(二分法**)

题目:

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

一刷:

看数字出现的规律,最小的数左边不会比它大,右边不会比它小,最差的解法是暴力搜索,时间复杂度为O(n),很自然可以想到利用折半查找的方式对其进行优化。

分析指针mid指向中间,left指向最左,right指向最优,那么只会出现三种情况

1. mid < right :mid到right是顺序递增的,最小值在mid或者left到mid之间,right指向mid,更新mid

2. mid > right : mid到right是乱序的,说明最小值在mid到right之间,left指向mid+1,更新mid

3. mid == right: 最小值在mid左右两端都有可能,这个时候缩小right边界

循环方式有了,就差一个停止条件,left + 1 :>= right

最后判断一下,mid比左边大,就返回left,否则返回right就行

class Solution:
    def minArray(self, numbers: List[int]) -> int:
        if numbers == []:
            return None
        if len(numbers) == 1:
            return numbers[0]
        left = 0
        right = len(numbers) - 1
        while(left < right):
            mid = ((right - left) >> 1) + left
            if numbers[mid] < numbers[right]:
                right = mid
            elif numbers[mid] > numbers[right]:
                left = mid + 1
            else:
                right -= 1
        return numbers[left]

12. 矩阵中的路径:dfs(*)

题目:

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

[["a","b","c","e"],
["s","f","c","s"],
["a","d","e","e"]]

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

示例 1:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true

一刷:很容易想到要用深度优先遍历来进行,写法上需要注意的地方有很多

1. 停止递归条件:

返回False: i和j越界,当前值不等于word[k]

返回True: k == len(word) - 1时

2. 访问过的元素标记

在往后遍历前将其变为‘\’表示访问过了,遍历结束后还得记得变为原来的值

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        word_len = len(word)
        row = len(board) - 1
        col = len(board[0]) - 1
        def dfs(i: int, j: int, k: int) -> bool:
            # 超出边界
            if (i < 0) or (i > row) or (j < 0) or (j > col) or(board[i][j] != word[k]):
                return False
            if k == word_len - 1:
                return True
            # 记录访问过的***********
            tmp, 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] = tmp
            return res
        for i in range(row+1):
            for j in range(col+1):
                if dfs(i, j, 0):
                    return True
        return False

ps:注意| 和or的执行时间有何区别?(将res赋值语句中的or改成|为何通过不了)

要知道为什么可以参考Python中 I、& 和 and、or在逻辑运算时有何不同

13. 机器人的运动范围:Bfs(*)

题目:

地上有一个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。请问该机器人能够到达多少个格子?

一刷:一刷用了笨方法,用的DFS, 记录从远点开始走过的节点。

class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        # 记录访问过的节点
        visited_nodes = []
        def qut(num:int) -> int:
            return num // 100 + (num % 100) // 10 + (num % 10)
        def dfs(row: int, col:int) -> bool:
            if (row < 0) or (row >=m) or (col < 0) or (col >= n) or ((row, col) in visited_nodes):
                return False
            if qut(row) + qut(col) > k:
                return False
            visited_nodes.append((row, col))
            dfs(row - 1, col)
            dfs(row + 1, col)
            dfs(row, col-1)
            dfs(row, col+1)
            return True
        dfs(0, 0)
        return len(visited_nodes)

 其实这道题的思路应该是广度优先遍历

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。ps:2<=n<=58

例如

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1  
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36

一刷:

数学推导

class Solution:
    def cuttingRope(self, n: int) -> int:
        # 小于3,按题目要求(m>1),需切除一个1:
        if n <= 3:
            return n-1
        else:
            m = n // 3
            if n % 3 == 2:
                return 2 * 3 ** m 
            elif n % 3 == 1:
                return 4 * 3 ** (m-1)
            else:
                return 3 ** m

贪心思想——>从初始取值开始,找到合理切分的规律

14-II. 剪绳子2:(在剪绳子1的基础上多了大数求余(循环求余,快速幂求余)**)

题目:

给你一根长度为 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。ps:2<=n<=1000

大数求余————>:

1.当m增大时,最后返回的3^m大小以指数级别增长,可能超出int32甚至int64的取值范围,导致返回值错误。

由于语言特性,理论上 Python 中的变量取值范围由系统内存大小决定(无限大),因此在 Python 中其实不用考虑大数越界问题。

2.在仅使用int32类型存储的前提下,正确计算x^m对p求余的值

3.解决方式有循环求余、快速幂求余,其中后者的时间复杂度更低

4.求余思路——>(xy)⊙p=[(x⊙p)(y⊙p)]⊙p

 

15. 二进制中1的个数:(位运算)

题目:

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

一刷:逐位判断,时间复杂度O(logn)

class Solution:
    def hammingWeight(self, n: int) -> int:
        num = 0
        while(n != 0):
            if n % 2 == 1:
                num += 1
            n = n >> 1
        return num

 当然用&运算更好,直接将n&1相与,不过在小数据下差别不大

class Solution:
    def hammingWeight(self, n: int) -> int:
        num = 0
        while(n != 0):
            num += n & 1
            n >>= 1
        return num

 更优的方法是利用n&(n-1)巧解

n&(n-1): 二进制数字n最右边的1变成0,其余不变, 只需要在循环中消去1即可,时间复杂度从O(log_{2}n)降为O(m),m为1的个数

class Solution:
    def hammingWeight(self, n: int) -> int:
        num = 0
        while n:
            num += 1
            n = n&(n-1)
        return num

 

16. 数值的整数次方:(快速幂**)

题目:实现函数duoble power(duoble base, int exponent), 求base的exponet次方,不得使用库函数,同时不需要考虑大数问题

一刷:利用剪绳子2中提到的快速幂思想来解

class Solution:
    def myPow(self, x: float, n: int) -> float:
        # 将n处理成正数
        if n<0: x, n = 1/x, -n
        rem = 1
        while(n):
            if n%2: rem = rem * x
            x = x**2
            n >>= 1
        return rem

 

17. 打印从1到最大的n位数:(将该题推广到大数范围*)

题目:输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999,leetcode上的list类型为int,没考虑大数。

class Solution:
    def printNumbers(self, n: int) -> List[int]:
        # result = [x for x in range(1, 10**n)]
        return list(range(1, 10**n))

 (将该题推广到大数范围*)

1. 大数只能用string类型来存储

2. 使用int类型,每轮可以通过+1生成下个数字,而此方法无法应用至String类型。并且,String类型的数字的进位操作效率较低,列如“9999” 至 "10000" 需要从个位到千位循环判断,进位4次。 *生成列表实际上是n位0-9的全排列,因此可避开进位操作,通过递归生成数字的String列表。基于分治算法的思想,先固定高位,向低位递归,当个位已被固定时,添加数字的字符串。列如,当n=2时(数字范围1-99),固定十位为0-9,按顺序依次开启递归,终止递归并添加数字字符串。

class Solution:
    def printNumbers(self, n: int) -> List[int]:
        def dfs(x):
            if x == n: # 终止条件,以固定所有位
                # 考虑去除高位的0
                s = "".join(num[self.start:])
                if s != '0': res.append("".join(s)) #拼接num并添加至res尾部
                if n - self.start == self.nine: self.start -= 1
                return
            for i in range(10): # 遍历0-9
                num[x] = str(i) # 固定第x位为i
                if i == 9:
                    self.nine += 1
                dfs(x + 1) # 开始固定第x+1位
            self.nine -= 1
        
        num = ['0']*n # 起始数字定义为n个0组成的字符列表
        res = [] # 数字字符串列表
        self.start = n-1
        self.nine = 0
        dfs(0) #开启全排列递归
        # res = [int(x) for x in res]
        return ",".join(res)

32-I. 从上到下打印二叉树(二叉树的层次遍历BFS,Python 中使用 collections 中的双端队列*)

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

给定二叉树: [3,9,20,null,null,15,7]

输出:[3,9,20,15,7]

Python 中使用 collections 中的双端队列 deque() ,其 popleft() 方法可达到 O(1) 时间复杂度;列表 list 的 pop(0) 方法时间复杂度为 O(N)

class Solution:
    def levelOrder(self, root: TreeNode) -> List[int]:
        if not root: return []
        queue, res = [], []
        queue.append(root)
        while queue:
            cur = queue.pop(0)
            if cur.left: queue.append(cur.left)
            if cur.right: queue.append(cur.right)
            res.append(cur.val)
        return res

其原因是: list 是列表,也就是 java c++ 中的数组,数组移除头部元素的方式 是把后面的元素全部往前移动一位,所以复杂度是 O(N) ; deque 是双端队列,底层是链表,因此头部和尾部是等价的,插入删除都是 O(1) 

class Solution:
    def levelOrder(self, root: TreeNode) -> List[int]:
        if not root: return []
        queue, res = collections.deque(), []
        queue.append(root)
        while queue:
            cur = queue.popleft()
            if cur.left: queue.append(cur.left)
            if cur.right: queue.append(cur.right)
            res.append(cur.val)
        return res

 32-II. 从上到下打印二叉树(一个queue实现*)

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

给定二叉树: [3,9,20,null,null,15,7]

输出

[
  [3],
  [9,20],
  [15,7]
]

第一次刷用了两个queue,带来了额外的空间开销

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root: return []
        queue1, queue2, res, cur_layer = collections.deque(), collections.deque(), [], []
        queue1.append(root)
        while queue1 or queue2:
            cur_layer = []
            while(queue1):
                cur = queue1.popleft()
                if cur.left: queue2.append(cur.left)
                if cur.right: queue2.append(cur.right)
                cur_layer.append(cur.val)
            if cur_layer: res.append(cur_layer)
            cur_layer = []
            while(queue2):
                cur = queue2.popleft()
                if cur.left: queue1.append(cur.left)
                if cur.right: queue1.append(cur.right)
                cur_layer.append(cur.val)
            if cur_layer: res.append(cur_layer)
        return res

其实只需要添加额外的一个数组,管理一下每层遍历的过程就好

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root: return []
        queue, res = collections.deque(), []
        queue.append(root)
        while queue:
            tmp = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                if cur.left: queue.append(cur.left)
                if cur.right: queue.append(cur.right)
                tmp.append(cur.val)
            res.append(tmp)
        return res

  32-III. 从上到下打印二叉树(一个queue实现*)

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

给定二叉树: [3,9,20,null,null,15,7]

输出:

[
  [3],
  [20,9],
  [15,7]
]

第一次刷用的是层次遍历 + 倒序的方式

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root: return []
        queue, res = collections.deque(), []
        queue.append(root)
        count = 0
        while queue:
            tmp = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                if cur.left: queue.append(cur.left)
                if cur.right: queue.append(cur.right)
                tmp.append(cur.val)
            count += 1
            res.append(tmp if len(res)%2 == 0 else tmp[::-1])
        return res

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值