题目名称:路径总和
给你二叉树的根节点 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
解释:由于树是空的,所以不存在根节点到叶子节点的路径。
/**
* 解法一:递归(先序遍历)
* 思路:
* 既然是检查从根到叶子有没有一-条等于目标值的路径,那肯定需要从根节点遍历到叶子,
* 我们可以在根节点每次往下一层的时候,将sum减去节点值,最后检查是否完整等于0.而
* 遍历的方法我们可以选取二叉树常用的递归先序遍历,因为每次进入一个子节点,更新
* sum值以后,相当于对子树查找有没有等于新目标值的路径,因此这就是子问题
* 时间复杂度:O(n),先序遍历二叉树所有结点
* 空间复杂度:O(n),最坏情况二叉树化为链表,递归栈空间最大为n
*/
function hasPathSum(root: TreeNode | null, targetSum: number): boolean {
if (root == null) return false;
if (root.left == null && root.right == null && root.val === targetSum)
return true;
return (
hasPathSum(root.left, targetSum - root.val) ||
hasPathSum(root.right, targetSum - root.val)
);
}
/**
* 解法二:非递归(DFS)
* 思路:
* 在二叉树中能够用递归解决的问题,很多时候我们也可以用非递归来解决。这里遍历过程
* 也可以使用栈辅助,进行dfs遍历,检查往下的路径中是否有等于sum的路径和。
* 注意,这里仅是dfs,而不是先序遍历,左右节点的顺序没有关系,因为每次往下都是单
* 独添加某个节点的值相加然后继续往下,因此左右节点谁先遍历不管用。
* 时间复杂度:O(n),DFS遍历二叉树所有结点
* 空间复杂度:O(n),最坏情况二叉树化为链表,递归栈空间最大为n
*/
function hasPathSum(root: TreeNode | null, targetSum: number): boolean {
if (root == null) return false;
const treeNodeStack: TreeNode[] = [];
const valueStack: number[] = [];
treeNodeStack.push(root);
valueStack.push(root.val);
while (treeNodeStack.length) {
const node = treeNodeStack.pop(); // 弹出相应节点
const valSum = valueStack.pop(); // 获取到该节点为止的路径和
// 是叶子结点且当前路径和等于 valSum
if (node.left == null && node.right == null && valSum === targetSum)
return true;
// 左节点&对应路径和入栈
if (node.left != null) {
treeNodeStack.push(node.left);
valueStack.push(node.left.val + valSum);
}
// 右节点&对应路径和入栈
if (node.right != null) {
treeNodeStack.push(node.right);
valueStack.push(node.right.val + valSum);
}
}
return false;
}