二叉树的路径问题

最近刷LeetCode里树的专题时,有一系列跟路径有关的题目,比如:路径总和(看是否存在一条路径的总和为某一数值、返回所有总和为某一数值的路径)、二叉树的所有路径、二叉树的最大(最小)深度。这些都与路径有关即深度优先遍历,套路也差不多,稍微改动一下即可。

一、【LeetCode 112】路径总和

1.题目描述

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

说明: 叶子节点是指没有子节点的节点。

示例:
给定如下二叉树,以及目标和 sum = 22,

          5
         / \
        4   8
       /   / \
      11  13  4
     /  \      \
    7    2      1

返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。

2.思路

(1)首先定义一个深度优先遍历的辅助函数DFS(self, root, result, path)来获取该二叉树的所有路径:

  • 定义出口:若当前节点的左节点和右节点均不存在(说明走到叶子节点)并且路径值之和等于给定的数值,则直接将该路径添加到result里面;
  • 接下来就是递归,若当前节点的左节点不为空,则将左节点添加至已有路径中self.DFS(root.left, result, path + [root.left.val]);同理,若右节点不为空,也将右节点添加至已有路径中self.DFS(root.right, result, path + [root.right.val])

(2)回到主函数:

  • 首先判空,若树不存在直接返回False即可;
  • 接着调用DFS函数,得到result:判断若result不为空,说明里面包含了路径也即表明存在这样一条路径等于给定值,返回True;否则直接返回False。

3.代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        result = []
        if not root:
            return False
        self.sum = sum
        self.DFS(root, result, [root.val])
        if result:
            return True
        return False

    def DFS(self, root, result, path):
        if not root.left and not root.right and sum(path) == self.sum:
            result.append(path)
        if root.left:
            self.DFS(root.left, result, path + [root.left.val])
        if root.right:
            self.DFS(root.right, result, path + [root.right.val])

二、【LeetCode 113】路径总和II

1.题目描述

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

说明: 叶子节点是指没有子节点的节点。

示例:
给定如下二叉树,以及目标和 sum = 22,

          5
         / \
        4   8
       /   / \
      11  13  4
     /  \    / \
    7    2  5   1

返回:

[
[5,4,11,2],
[5,8,4,5]
]

2.思路

跟112题的思路几乎一模一样,只不过112题是看是否存在这样一条路径,本题是返回所有满足要求的路径,DFS函数里不用改动,直接在主函数里返回result即可。

3.代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
        result = []
        if not root:
            return result
        self.sum = sum
        self.DFS(root, result, [root.val])
        return result

    def DFS(self, root, result, path):
        if not root.left and not root.right and sum(path) == self.sum:
            result.append(path)
        if root.left:
            self.DFS(root.left, result, path + [root.left.val])
        if root.right:
            self.DFS(root.right, result, path + [root.right.val])

三、【LeetCode 257】二叉树的所有路径

1.题目描述

给定一个二叉树,返回所有从根节点到叶子节点的路径。

说明: 叶子节点是指没有子节点的节点。

示例:

输入:

   1
 /   \
2     3
 \
  5

输出: [“1->2->5”, “1->3”]

解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3

2.思路

思路与上面两题大同小异,还少了一个确定路径总和的步骤,辅助函数DFS可不变,只不过该题的输出有点变化,类似于链表,要用到join()函数将数组self.result里的元素先变成字符串,再用’->'连接起来输出即可。

3.代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        self.result = []
        if not root:
            return []
        self.DFS(root, [root.val])
        self.result = ['->'.join([str(i) for i in item]) for item in self.result]
        return self.result
        
    def DFS(self, root, path):
        if not root.left and not root.right:
            self.result.append(path)
        if root.left:
            self.DFS(root.left, path + [root.left.val])
        if root.right:
            self.DFS(root.right, path + [root.right.val])

四、【LeetCode 111】二叉树的最小深度

1.题目描述

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

示例:

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

    3
   / \
  9  20
    /  \
   15   7

返回它的最小深度 2.

2.思路

最初的思路是按照257题那样把所有路径列出来,然后求出长度最小的路径即为最小深度,于是就有了下面的代码,这样看起来有点像暴力法,虽说没有超出时间限制,但是运行时间真的慢,所以参考了别人的题解之后,觉得有一种方法很赞,见第四部分。

3.代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        result = []
        self.DFS(root, result, [root.val])
        res = []
        for li in result:
            res.append(len(li))
        return min(res)

    def DFS(self, root, result, path):
        if not root.left and not root.right:
            result.append(path)
        if root.left:
            self.DFS(root.left, result, path + [root.left.val])
        if root.right:
            self.DFS(root.right, result, path + [root.right.val])

4.优化后的代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        if not root.left and not root.right:
            return 1
        if not root.left and root.right:
            return self.minDepth(root.right) + 1
        if root.left and not root.right:
            return self.minDepth(root.left) + 1
        else:
            return min(self.minDepth(root.left), self.minDepth(root.right)) + 1

与第3部分的代码相比,这个就更清爽直接一些:
(1)若树不存在,就直接返回0;
(2)若只有根节点或者到叶子节点时就返回1;
(3)若当前节点的左子树不存在,右子树存在,则对右子树进行递归计算深度;
(4)若当前节点的左子树存在,右子树不存在,同理;
(5)左子树和右子树同时存在的时候,就取两者的最小值 + 1(加一是表示当前子树的父节点)

五、【LeetCode 104】二叉树的最大深度

1.题目描述

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

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

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

2.思路

和【二叉树的最小深度】思路一模一样,一个求最小值,一个求最大值。

3.代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        if not root.left and not root.right:
            return 1
        if not root.left and root.right:
            return self.maxDepth(root.right) + 1
        if root.left and not root.right:
            return self.maxDepth(root.left) + 1
        else:
            return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1

六、【LeetCode 129】求根到叶子节点数字之和

1.题目描述

给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。

例如,从根到叶子节点路径 1->2->3 代表数字 123。

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

说明: 叶子节点是指没有子节点的节点。

示例 1:

输入: [1,2,3]

    1
   / \
  2   3

输出: 25
解释:
从根到叶子节点路径 1->2 代表数字 12.
从根到叶子节点路径 1->3 代表数字 13.
因此,数字总和 = 12 + 13 = 25.

2.第一种代码

在遍历的节点的时候就将节点值转换为字符串连接,最后将得到的字符串转换为整型相加即可。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        self.res = 0
        if not root:
            return 0
        self.DFS(root, '')
        return self.res
        
    def DFS(self, root, tmp):
        if not root.left and not root.right:
            self.res += int(tmp + str(root.val))
        if root.left:
            self.DFS(root.left, tmp + str(root.val))
        if root.right:
            self.DFS(root.right, tmp + str(root.val))

3.第二种代码

思路和前几题类似,用到了深度优先遍历辅助函数DFS,还是先得到所有的路径,然后处理这个存有所有路径的列表:先对每个路径中的每个元素的十分位,百分位或千分位进行转换,然后使用sum()函数求和即可得到一个连续的路径表示,最后将这些值相加即可。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        result = []
        if not root:
            return 0
        self.DFS(root, result, [root.val])
        values = []
        for item in result:
            res = [i *10**index for index,i in enumerate(item[::-1])]
            value = sum(res)
            values.append(value)
        val = sum(values)
        return val

    def DFS(self, root, result, path):
        if not root.left and not root.right:
            result.append(path)
        if root.left:
            self.DFS(root.left, result, path + [root.left.val])
        if root.right:
            self.DFS(root.right, result, path + [root.right.val])

补充

a = [1, 2, 3, 4, 5]
a = [i *10**index for index, i in enumerate(a[::-1])
b = sum(a)
print(b)
输出:12345
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值