博客主页:@花无缺
欢迎 点赞 收藏⭐ 留言 加关注✅!
本文由 花无缺 原创收录于专栏 【力扣题解】
P112. 路径总和
给你二叉树的根节点 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
广度优先搜索递归(详细代码):
public boolean hasPathSum(TreeNode root, int targetSum) {
// 空树, 返回 false
if (root == null) {
return false;
}
return dfs(root, targetSum - root.val);
}
public boolean dfs(TreeNode node, int count) {
// 当前节点是叶子节点并且 count == 0, 说明找到了题目要求的路径
// 返回 true, 递归终止
if (node.left == null && node.right == null && count == 0) {
return true;
}
// count != 0, 不是题目要求的路径, 直接返回 false, 递归终止
if (node.left == null && node.right == null) {
return false;
}
// 递归左子树
if (node.left != null) {
// 处理左子节点的 count 值
count = count - node.left.val;
// 如果左子节点满足了题目要求的路径, 直接返回 true
if (dfs(node.left, count)) {
return true;
}
// 回溯, 将 count 恢复之前的值
count = count + node.left.val;
}
// 递归右子树
if (node.right != null) {
// 处理右子节点的 count 值
count = count - node.right.val;
// 如果右子节点满足了题目要求的路径, 直接返回 true
if (dfs(node.right, count)) {
return true;
}
// 回溯, 将 count 恢复之前的值
count = count + node.right.val;
}
// 树的所有路径都不满足题目条件, 返回 false
return false;
}
广度优先搜索递归(简化代码):
public boolean hasPathSum(TreeNode root, int targetSum) {
// 空树, 返回 false
if (root == null) {
return false;
}
// 如果当前节点是叶子节点并且 targetSum 等于当前节点值
// 说明找到了题目要求的路径
if (root.left == null && root.right == null && targetSum == root.val) {
return true;
}
// 没有找到路径, 继续递归遍历左子树和右子树
// 此时要将 targetSum 减去当前节点值, 表示遍历进入了当前节点的下一节点
// 所以要把当前节点值减去
// 当遍历到符合条件的叶子节点时, targetSum 就已经递减到和叶子节点值相等了
// 如果左右子树都不符合, 那么返回时(回溯), targetSum 的大小并没有改变
return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
}
时间复杂度:O(n)
,要遍历树的所有节点一次,树的节点数为 n。
深度优先搜索:
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) {
return false;
}
Queue<TreeNode> nodeQueue = new LinkedList<>();
Queue<Integer> valQueue = new LinkedList<>();
nodeQueue.offer(root);
valQueue.offer(root.val);
while (!nodeQueue.isEmpty()) {
TreeNode node = nodeQueue.poll();
int val = valQueue.poll();
// 当前节点是叶子节点
if (node.left == null && node.right == null) {
// 当前路径和等于 targetSum, 返回 true
if (val == targetSum) {
return true;
// 否则继续遍历
} else {
continue;
}
}
// 遍历左子树
if (node.left != null) {
// 左子节点进队
nodeQueue.offer(node.left);
// 将左子节点的值加入路径和中
valQueue.offer(node.left.val + val);
}
// 遍历右子树
if (node.right != null) {
// 右子节点进队
nodeQueue.offer(node.right);
// 将右子节点的值加入路径和中
valQueue.offer(node.right.val + val);
}
}
return false;
}
时间复杂度:O(n)
,要遍历树的所有节点一次,树的节点数为 n。
这个题要求我们找到一条路径的和等于指定值 targetSum,那么我们肯定要先遍历这棵树,遍历这棵树的过程中同时判断当前路径的节点总和是否等于 targetSum,那么我们就要每经过一个节点将当前路径的节点值累加,这样的查找是很麻烦的,我们可以换个思路,当找到符合条件的叶子节点时,路径累加的和刚好等于 targetSum,那么我们可以从第一个节点开始依次将 targetSum 将去当前节点值,当找到符合条件的路径的最后一个节点(叶子结点)时,targetSum 刚好等于 0。根据这个我们可以写出深度优先搜索的递归代码。
这个题我们也可以使用广度优先搜索的方法来做,但是要借助两个队列,一个队列用来对树进行层次遍历,存储节点,一个队列用来存储路径和,我们在遍历树的过程中,每遍历一个节点就将节点值累加并加入节点值队列 valQueue,这个节点值刚好对应当前节点之前的路径和,所以每次将当前节点和节点值出队,就可以判断路径和是否等于 targetSum,从而达到题目效果。
作者:花无缺(huawuque404.com)
欢迎
关注
我的博客:花无缺-每一个不曾起舞的日子都是对生命的辜负~
一起进步-刷题专栏:【力扣题解】
往期精彩好文:
【CSS选择器全解指南】
【HTML万字详解】
你们的点赞 收藏⭐ 留言 关注✅
是我持续创作,输出优质内容
的最大动力!
谢谢!