一、题目描述
给你二叉树的根节点 root
和一个表示目标和的整数 targetSum
。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
。如果存在,返回 true
;否则,返回 false
。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 输出:true 解释:等于目标和的根节点到叶节点路径如上图所示。
示例 2:
输入:root = [1,2,3], targetSum = 5 输出:false 解释:树中存在两条根节点到叶子节点的路径: (1 --> 2): 和为 3 (1 --> 3): 和为 4 不存在 sum = 5 的根节点到叶子节点的路径。
示例 3:
输入:root = [], targetSum = 0 输出:false 解释:由于树是空的,所以不存在根节点到叶子节点的路径。
提示:
- 树中节点的数目在范围
[0, 5000]
内 -1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
二、解题思路
我们需要找到一条从根节点到叶子节点的路径,使得路径上所有节点的值之和等于 targetSum
。我们可以使用深度优先搜索(DFS)来解决这个问题。具体步骤如下:
-
递归函数定义:定义一个递归函数
hasPathSum
,该函数接受当前节点node
和当前路径和currentSum
作为参数。 -
递归终止条件:如果当前节点
node
为空,返回 false,因为没有更多的节点可以检查。 -
更新当前路径和:将当前节点的值加到
currentSum
上。 -
判断是否为叶子节点:如果当前节点是叶子节点(即没有子节点),检查
currentSum
是否等于targetSum
。如果是,返回 true;否则,返回 false。 -
递归搜索:如果当前节点不是叶子节点,递归地调用
hasPathSum
函数,参数是当前节点的左子节点和currentSum
,以及当前节点的右子节点和currentSum
。 -
返回结果:如果两个递归调用中的任何一个返回 true,则返回 true;否则,返回 false。
三、具体代码
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) {
return false;
}
return hasPathSum(root, targetSum, 0);
}
private boolean hasPathSum(TreeNode node, int target, int currentSum) {
if (node == null) {
return false;
}
currentSum += node.val;
if (node.left == null && node.right == null && currentSum == target) {
return true;
}
return hasPathSum(node.left, target, currentSum) || hasPathSum(node.right, target, currentSum);
}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
-
递归函数调用次数:对于每个节点,我们最多会调用一次
hasPathSum
函数。因此,对于一个有 n 个节点的树,最坏情况下,函数会被调用 n 次。 -
单次递归调用的时间复杂度:对于每个节点的单次递归调用,我们需要执行常数时间操作,如判断当前节点是否为空、更新当前路径和、判断是否为叶子节点等。
- 综上所述,总的时间复杂度是 O(n),其中 n 是树中节点的数量。
2. 空间复杂度
-
递归调用栈:递归调用会使用系统栈来存储每一层递归的信息。在最坏的情况下,树可能是一个完全二叉树,此时递归调用栈的深度为 O(h),其中 h 是树的高度。
-
其他空间:除了递归调用栈之外,我们不需要额外的空间来存储节点的信息,因此这部分的空间复杂度是 O(1)。
- 综上所述,总的空间复杂度是 O(h),在最坏情况下是 O(n)。
五、总结知识点
-
递归函数:
hasPathSum
函数是一个递归函数,它接受当前节点、目标和当前路径和作为参数,并递归地检查左子树和右子树。 -
二叉树的遍历:通过递归的方式,代码实现了对二叉树的遍历,从根节点开始,逐层向下,直到到达叶子节点。
-
路径和的概念:代码中维护了一个变量
currentSum
,用于跟踪从根节点到当前节点的路径上所有节点值之和。 -
叶子节点的判断:通过检查当前节点的左右子节点是否都为空来确定一个节点是否是叶子节点。
-
条件语句:代码中使用了
if
条件语句来判断节点是否为空、是否为叶子节点以及路径和是否等于目标。 -
递归终止条件:递归函数在遇到空节点时返回 false,这是递归的终止条件。
-
逻辑运算符:代码中使用了逻辑运算符
||
来组合两个递归调用,如果任意一个调用返回 true,则整个表达式返回 true。 -
函数的封装:
hasPathSum
函数被定义为private
,这意味着它只能在同一个类中被访问,这是封装的一种形式。 -
树的表示:代码中使用了
TreeNode
类来定义二叉树的节点,这是二叉树数据结构的基本表示方法。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。