算法题目 深度优先(dfs)+递归

Posted by SunQH Blog on February 13, 2021

leetcode题目按类型

深度优先搜索DFS+递归

dfs(回溯)算法框架

  1. **核心**

    :for循环里面的递归,在递归调用之前做选择,在调用之后撤销选择。

  2. 3个问题:
    1. 路径:已经做的选择
    2. 选择列表:当前可做的选择
    3. 结束条件:到达决策树底层,无法再做选择的条件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def backtrack(选择列表, path):
	if 满足结束条件:
    result.add(path)
    return 
  
  for 选择 in 选择列表:
    path.append(选择)
    backtrack(选择列表, path)
    path.pop()

result = []
path = []
backtrack(选择列表, path)
return result
  1. 带有visited的dfs框架:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def DFS(选择列表, path):
	if 满足结束条件:
    result.add(path)
    return 
  
  visited.add(start)
  for 选择 in 选择列表:
    path.append(选择)
    backtrack(选择列表, path)
    path.pop()
  visited.remove(start)

visited = set()
result = []
path = []
DFS(选择列表, path)
return result

二叉树的dfs(路径总和2)

  1. 选择只有左子树和右子树
  2. 无需 visited
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def dfs(root, targetSum):        
    if not root:
        return   # 注意 return  
    
    path.append(root.val)  # 添加路径
    
    targetSum -= root.val
    if not root.left and not root.right and targetSum == 0: # 如果满足条件
        res.append(path[:])        
    
    dfs(root.left, targetSum)
    dfs(root.right, targetSum)
    
    path.pop()  						# 注意要 去掉路径

res = []
path = []
dfs(root,targetSum)
return res

46. 全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

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

✅(5m)

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        def helper(path, nums):
            if len(path) == len(nums):
                res.append(path)
            for i in nums:
                if i not in path:
                    helper(path+[i], nums)
        
        res = []
        path = []   
        helper(path, nums)     
        return res

总结:

  1. 在basecase里,注意,满足条件了就要return出去
  2. 组合问题需要做选择前添加判断,跳过不满足条件的选择

✅(20m)79. 单词搜索

给定一个二维网格和一个单词,找出该单词是否存在于网格中。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

1
# 示例board =[  ['A','B','C','E'],  ['S','F','C','S'],  ['A','D','E','E']]给定 word = "ABCCED", 返回 true给定 word = "SEE", 返回 true给定 word = "ABCB", 返回 false

✅(20m)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]   
        def check(i: int, j: int, k: int) -> bool:
            if board[i][j] != word[k]:
                return False
            if k == len(word) - 1:
                return True

            visited.add((i, j))
            result = False
            for di, dj in directions:
                newi, newj = i + di, j + dj
                if 0 <= newi < len(board) and 0 <= newj < len(board[0]):
                    if (newi, newj) not in visited:
                        if check(newi, newj, k + 1):
                            result = True
                            break

            visited.remove((i, j))
            return result

        h, w = len(board), len(board[0])
        visited = set()
        for i in range(h):
            for j in range(w):
                if check(i, j, 0):
                    return True

        return False

总结

leetcode全排列解析+回溯人们详解+练习

DFS 、动态规划、回溯法、递归之间的关系是什么?

回溯搜索是深度优先搜索(DFS)的一种。对于某一个搜索树来说(搜索树是起记录路径和状态判断的作用),回溯和DFS,其主要的区别是,回溯法在求解过程中不保留完整的树结构,而深度优先搜索记下完整的搜索树。为了减少存储空间,在深度优先搜索中,用标志的方法记录访问过的状态,这种处理方法使得深度优先搜索法与回溯法没什么区别了。

递归就是自我调用,经常作为一种编程的实现方式,比如题主问题中的DFS 、动态规划、回溯法都可以用递归来实现,当然也可以用非递归来实现。很多时候一个概念也可以用递归的方式来定义(比如gnu)。

回溯是一种通用的算法,把问题分步解决,在每一步都试验所有的可能,当发现已经找到一种方式或者目前这种方式不可能是结果的时候,退回上一步继续尝试其他可能。很多时候每一步的处理都是一致的,这时候用递归来实现就很自然。

深度优先搜索是当回溯用于树的时候。当然了,几乎所有可以用回溯解决的问题都可以表示为树。那么这俩在这里就几乎同义了。如果一个问题解决的时候显式地使用了树,那么我们就叫它dfs。很多时候没有用树我们也管它叫dfs严格地说是不对的,但是dfs比回溯打字的时候好输入。别的回答里提到了砍枝,实际上这二者都可以砍枝。

动态规划,回溯可以用于所有用穷举法可以解决的问题,而DP只用于**具有最优子结构的问题**。所以不是所有问题都适合用dp来解决,比如八皇后。dp需要存贮子问题的解,回溯不需要。

回溯算法

  1. 深度优先遍历的特有的现象,节约空间
    全排列思路:
    在枚举第一位的时候,有 3 种情况。
    在枚举第二位的时候,前面已经出现过的数字就不能再被选取了;
    在枚举第三位的时候,前面 2 个已经选择过的数字就不能再被选取了。
    image.png

第 1 步都是先画图,画图是非常重要的,只有画图才能帮助我们想清楚递归结构,想清楚如何剪枝

步骤,即在画图的过程中思考清楚:

1、分支如何产生;

2、题目需要的解在哪里?是在叶子结点、还是在非叶子结点、还是在从跟结点到叶子结点的路径?

3、哪些搜索是会产生不需要的解的?例如:产生重复是什么原因,如果在浅层就知道这个分支不能产生需要的结果,应该提前剪枝,剪枝的条件是什么,代码怎么写?

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

数组深拷贝、浅拷贝

1
res.append(path[:])  # 注意相当于这里做一次拷贝。否则输出为全空
1
# 浅拷贝, 指向同一地址a = [2,3,34,4]b = aa.append(222)a, b
1
# 深拷贝, 不同地址a = [2,3,34,4]b = a[:]c = list(a)d = a*1import copye = copy.copy(a)a.append(222)a, b, c, d, e

步骤

  1. 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。
  2. 当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。
  3. 如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。

概括

深度优先搜索的步骤分为

  1. 递归下去
  2. 回溯上来。

顾名思义,深度优先,则是以深度为准则,先一条路走到底,直到达到目标。这里称之为递归下去。

否则既没有达到目标又无路可走了,那么则退回到上一步的状态,走其他路。这便是回溯上来。

———————————-

🚩(20m) 101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

1
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。    1   / \  2   2 / \ / \3  4 4  3 但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:    1   / \  2   2   \   \   3    3  进阶:你可以运用递归和迭代两种方法解决这个问题吗?

2️⃣使用递归的思想

如果同时满足下面的条件,两个树互为镜像:

  1. 它们的两个根结点具有相同的值
  2. 每个树的右子树都与另一个树的左子树镜像对称
1
# guanjieclass Solution:    def isSymmetric(self, root: TreeNode) -> bool:        if not root: return         return self.check(root.left, root.right)            def check(self, left, right):        if left is None and right is None: return True        if left is None or right is None: return False        if left.val != right.val : return False        return self.check(left.left, right.right) and self.check(left.right, right.left)                            

🚩(60m) 394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

1
示例 1:输入:s = "3[a]2[bc]"输出:"aaabcbc"示例 2:输入:s = "3[a2[c]]"输出:"accaccacc"示例 3:输入:s = "2[abc]3[cd]ef"输出:"abcabccdcdcdef"示例 4:输入:s = "abc3[cd]xyz"输出:"abccdcdcdxyz"

2️⃣栈和递归使用

1
class Solution:    def decodeString(self, s: str) -> str:        def dfs(i):            res, multi = "", 0            while i<len(s):                if '0' <= s[i] <= '9':                    multi = multi*10 + s[i]                elif s[i] == '[':                    # 注意,返回i的含义是更新上层递归指针位置,因为内层递归已经吃掉一串str,若不跟新i,                    # 外层仍然从i+1开始,则会重复处理内层处理过的一串str。                    i, tmp = dfs(i+1)                      res += multi * tmp                    multi = 0                elif s[i] == ']':                    return i,res                else: res += s[i]                i+=1            return res        return dfs(0)

🚩105. 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。

注意:

你可以假设树中没有重复的元素。

例如,给出

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

2️⃣

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

🚩114. 二叉树展开为链表

给定一个二叉树,原地将它展开为一个单链表。

1
例如,给定二叉树    1   / \  2   5 / \   \3   4   6将其展开为:1 \  2   \    3     \      4       \        5         \          6
1
# 前序遍历class Solution:    def flatten(self, root: TreeNode) -> None:        """        Do not return anything, modify root in-place instead.        """        if root.left:            root.next = root.left        elif root.right:            root.next = flatten(root.left)

🚩(困难)679. 24 点游戏

你有 4 张写有 1 到 9 数字的牌。你需要判断是否能通过 *,/,+,-,(,) 的运算得到 24。

1
示例 1:输入: [4, 1, 8, 7]输出: True解释: (8-4) * (7-1) = 24示例 2:输入: [1, 2, 1, 2]输出: False注意:除法运算符 / 表示实数除法而不是整数除法例如 4 / (1 - 2/3) = 12 每个运算符对两个数进行运算特别是我们不能用 - 作为一元运算符例如[1, 1, 1, 1] 作为输入时表达式 -1 - 1 - 1 - 1 是不允许的你不能将数字连接在一起例如输入为 [1, 2, 1, 2] 不能写成 12 + 12 
1
class Solution:    def judgePoint24(self, nums: List[int]) -> bool:        for i in range(4):            if         def dfs(nums, depth):            
1
from typing import Listnums = [4, 1, 8, 7]solution = Solution()result = solution.judgePoint24(nums)result

✅(20m)79. 单词搜索

给定一个二维网格和一个单词,找出该单词是否存在于网格中。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

1
# 示例board =[  ['A','B','C','E'],  ['S','F','C','S'],  ['A','D','E','E']]给定 word = "ABCCED", 返回 true给定 word = "SEE", 返回 true给定 word = "ABCB", 返回 false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]

        def check(i: int, j: int, k: int) -> bool:
            if board[i][j] != word[k]:
                return False
            if k == len(word) - 1:
                return True
            
            visited.add((i, j))
            result = False
            for di, dj in directions:
                newi, newj = i + di, j + dj
                if 0 <= newi < len(board) and 0 <= newj < len(board[0]):
                    if (newi, newj) not in visited:
                        if check(newi, newj, k + 1):
                            result = True
                            break
            
            visited.remove((i, j))
            return result

        h, w = len(board), len(board[0])
        visited = set()
        for i in range(h):
            for j in range(w):
                if check(i, j, 0):
                    return True
        
        return False

2️⃣

✅ (20m) 46. 全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

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

2️⃣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:    
  def permute(self, nums: List[int]) -> List[List[int]]:        
    if depth == size:            
      res.append(path[:])            
      return                 
    for i in range(size):            
      if not used[i]:                
        used[i] = True                
        path.append(nums[i])                                
        dfs(nums, size, depth+1, path, used, res)                                
        used[i] = False                
        path.pop()                        
        size = len(nums)        
        if size == 0:            
          return []                
        used = [False for _ in range(size)]        
        res = []        
        dfs(nums, size, 0, [], used, res)        
        return res        
1
from typing import Listnums = [1,2,4]solution = Solution()result = solution.permute(nums)result

3️⃣

1
class Solution:    def __init__(self):        self.result = []     def permute(self, nums: List[int]) -> List[List[int]]:        def permute_sub(nums,path):            if len(path) == len(nums):                self.result.append(path[:])            for num in nums:                if num not in path:                    path.append(num) # 做选择                    permute_sub(nums,path) # 递归                    path.pop() # 撤销选择                permute_sub(nums,[])        return self.result

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        def helper(path, nums):
            if len(path) == len(nums):
                res.append(path)
            for i in nums:
                if i not in path:
                    helper(path+[i], nums)
        
        res = []
        path = []   
        helper(path, nums)     
        return res

总结:

  1. 在basecase里,注意,满足条件了就要return出去
  2. 组合问题需要做选择前添加判断,跳过不满足条件的选择

✅(60m) 51. N 皇后

难度困难725

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。

示例 1:

img

1
2
3
输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

1
2
输入:n = 1
输出:[["Q"]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
    def __init__(self):
        self.result = [] 
    def solveNQueens(self, n: int) -> List[List[str]]:
        def solveNQueens_sub(n, path, diagonal1, diagonal2):
            if len(path) == n:
                self.result.append(path[:])
            for num in range(n):
                if num not in path and len(path) - num not in diagonal1 and len(path) + num not in diagonal2:
                    diagonal1.add(len(path) - num)
                    diagonal2.add(len(path) + num)
                    path.append(num) # 做选择
                    solveNQueens_sub(n,path,diagonal1,diagonal2) # 递归
                    path.pop() # 撤销选择
                    diagonal1.remove(len(path) - num)  # 注意长度要是当前的长度,和上面的add保持一致
                    diagonal2.remove(len(path) + num)

        diagonal1, diagonal2 = set(), set()   # 用set定义更容易,复杂度比较低,为O(log(n))
        solveNQueens_sub(n,[],diagonal1,diagonal2)
        self.result.sort()
        return [["."*index + "Q" + (n-index-1)*"." for index in path] for path in self.result]

总结:

  1. 查找时可以考虑用 $set$,定义更容易,复杂度比较低,为$O(log(n))$。虽然 $dict$复杂度为 $O(1)$,但是由于有哈希化的过程,所以时间通常也没有少。

  2. 注意回溯前后,长度要是当前的长度,和上面的add保持一致

    1
    2
    3
    4
    5
    6
    7
    
                        diagonal1.add(len(path) - num)
                        diagonal2.add(len(path) + num)
                        path.append(num) # 做选择
                        solveNQueens_sub(n,path,diagonal1,diagonal2) # 递归
                        path.pop() # 撤销选择
                        diagonal1.remove(len(path) - num)  # 注意长度要是当前的长度,和上面的add保持一致
                        diagonal2.remove(len(path) + num)
    

🚩(30m)78. 子集

难度中等995

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

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

示例 2:

1
2
输入:nums = [0]
输出:[[],[0]]
1
class Solution:    def subsets(self, nums: List[int]) -> List[List[int]]:        def backtrack(nums,start,track):             res.append(track[:])            for i in range(start,len(nums)): # 从start开始可以避免重复                track.append(nums[i])                backtrack(nums,i+1,track)                track.pop()        res = []        track = []        backtrack(nums,0,track)        return res

✅(40m)77. 组合

难度中等499

给定两个整数 nk,返回 1 … n 中所有可能的 k 个数的组合。

示例:

1
2
3
4
5
6
7
8
9
10
输入: n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

总结:

  1. 回溯算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        def backtrack(start,path): 
            if len(path) == k:
                print(path)
                result.append(path[:])
            for i in range(start,n+1):
                path.append(i)
                backtrack(i+1,path)  # 注意这里是i+1
                path.pop()
        
        result = []
        path = []
        backtrack(1,path)
        return result
        

  1. 注意开始的位置: backtrack(i+1,path) # 注意这里是i+1, 这样才能保证每次都比当前大。

🚩 22. 括号生成

难度中等1566

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

1
2
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

1
2
输入:n = 1
输出:["()"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        def backtrack(left,right,track,res):
            if left<0 or right<0:
                return 
            if right < left:
                return 
            if left==0 and right ==0:
                res.append(track)
                return 
            
            backtrack(left-1,right,track+'(',res)
            backtrack(left,right-1,track+')',res)
        
        if n==0:
            return {}
        res = []
        track = ""
        backtrack(n,n,track,res)
        return res

🚩(30m) 17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例:

1
2
    输入:"23" 
    输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 

2️⃣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if not digits: return []

        phone = {'2':['a','b','c'],
                 '3':['d','e','f'],
                 '4':['g','h','i'],
                 '5':['j','k','l'],
                 '6':['m','n','o'],
                 '7':['p','q','r','s'],
                 '8':['t','u','v'],
                 '9':['w','x','y','z']}
                
        def backtrack(conbination,nextdigit):
            if len(nextdigit) == 0:
                res.append(conbination)
            else:
                for letter in phone[nextdigit[0]]:
                    backtrack(conbination + letter,nextdigit[1:])

        res = []
        backtrack('',digits)  # 路径, 选择
        return res

🚩(30m) 100. 相同的树

难度简单634收藏分享切换为英文接收动态反馈

给你两棵二叉树的根节点 pq ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        if not p and not q:
            return True
        elif not p or not q :
            return False
        elif p.val != q.val:
            return False
        else:
            return self.isSameTree(p.left,q.left) and self.isSameTree(p.right,q.right)
            

🚩(20m) 112. 路径总和

难度简单600收藏分享切换为英文接收动态反馈

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum

叶子节点 是指没有子节点的节点。

1
2
3
4
5
6
7
8
9
class Solution:
    def hasPathSum(self, root: TreeNode, targetSum: int) -> bool:
        if not root:
            return False   # 注意要return false!!!,因为是or
        targetSum -= root.val
        if not root.left and not root.right:
            return targetSum == 0      
        return self.hasPathSum(root.left, targetSum) or self.hasPathSum(root.right, targetSum)

1
2
    if not root:
        return False   # 注意要return false!!!,因为是or

🚩(30m) 113. 路径总和 II

难度中等508收藏分享切换为英文接收动态反馈

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
        res = []
        path = []
        def dfs(root, targetSum):        
            if not root:
                return   # 注意 return  
            
            path.append(root.val)  # 添加路径

            targetSum -= root.val
            if not root.left and not root.right and targetSum == 0:
                res.append(path[:])       
            dfs(root.left, targetSum)
            dfs(root.right, targetSum)
        
            path.pop()  # 注意要 去掉路径

        dfs(root,targetSum)
        return res

✅(30m) 129. 求根节点到叶节点数字之和

难度中等367收藏分享切换为英文接收动态反馈

给你一个二叉树的根节点 root ,树中每个节点都存放有一个 09 之间的数字。

每条从根节点到叶节点的路径都代表一个数字:

  • 例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123

计算从根节点到叶节点生成的 所有数字之和

叶节点 是指没有子节点的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        def dfs(root, path, res):
            if not root:
                return 

            path = path*10 + root.val
            # print(path)

            if not root.left and not root.right:
                res.append(path)

            dfs(root.left, path, res)
            dfs(root.right, path, res)

            path //= 10

        res = []  # 注意要把res定义成数组,才会才传参的过程改变
        path = 0
        dfs(root, path, res)

        return sum(res)

注意要把res定义成数组,才会才传参的过程改变

(30m) 🚩 222. 完全二叉树的节点个数

难度中等504收藏分享切换为英文接收动态反馈

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。