题目描述
给你二叉树的根节点 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
思路
递归法
递归三部曲:
- 确定递归函数的参数和返回值。参数:需要二叉树的根节点,还需要一个计数器,这个计数器用来计算二叉树的一条边之和是否正好是目标和,计数器为int型。返回值:bool类型,判断是否存在路径。
- 确定终止条件。不要去累加然后判断是否等于目标和,那样代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。如果最后count == 0,同时到了叶子节点的话,说明找到了目标和,返回true。如果遍历到了叶子节点,count不为0,就是没找到,返回false。
- 确定单层递归的逻辑。本题递归过程中会遇到不需要的路径,因此需要回溯,遇到了合适的路径要立即返回。本题没有中间节点的处理逻辑,因此前中后序的处理都一样。
代码
C++版:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
// 递归法,回溯
bool traversal(TreeNode* node,int count){
// 终止条件,到达叶子节点
if(node->left==NULL&&node->right==NULL&&count==0){
return true;
}
if(node->left==NULL&&node->right==NULL&&count!=0){
return false;
}
// 防止空指针操作,在递归前判空
if(node->left){
count-=node->left->val;
// 找到了合适的路径,应该立刻返回,包含了回溯
if(traversal(node->left,count)){
return true;
}
// 回溯
count+=node->left->val;
}
if(node->right){
count-=node->right->val;
// 找到了合适的路径,应该立刻返回
if(traversal(node->right,count)){
return true;
}
// 回溯
count+=node->right->val;
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == NULL) return false;
return traversal(root, targetSum-root->val);
}
};
Python版:
# 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 traversal(self, cur: TreeNode, count: int) -> bool:
if not cur.left and not cur.right and count == 0: # 遇到叶子节点,并且计数为0
return True
if not cur.left and not cur.right: # 遇到叶子节点直接返回
return False
if cur.left: # 左
count -= cur.left.val
if self.traversal(cur.left, count): # 递归,处理节点
return True
count += cur.left.val # 回溯,撤销处理结果
if cur.right: # 右
count -= cur.right.val
if self.traversal(cur.right, count): # 递归,处理节点
return True
count += cur.right.val # 回溯,撤销处理结果
return False
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if root is None:
return False
return self.traversal(root, targetSum - root.val)
需要注意的地方
1.递归函数是否需要返回值的三种情况:(1)如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(【113.路径总和II】);(2)如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (【236. 二叉树的最近公共祖先】);(3)如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题)
2.用从0累加的方式判断目标和的代码比较麻烦,用递减再判断最后是否为0的方式判断更方便。
3.我的理解:在递归中会遇到不需要的东西时需要回溯。