此题解法可借鉴:二叉树根节点到叶子节点和为指定值的路径 https://blog.nowcoder.net/n/3ca862f49e6c409cb111db77c12932e8
算法思想一:递归
解题思路:
采用递归遍历二叉树的路径节点,同时计算二叉树路径节点的数字之和,当到达叶子节点且路径的数字之和等于 sum 则说明二叉树中存在节点和为指定值的路径
算法步骤:
1、特殊情况:当二叉树为空,则返回 false
2、遍历根节点的左右子树,记录根节点的数字之和 res
当节点的左右子树均为空,且 res == sum,则返回 true
3、递归 该节点的左右子树,做上述计算
代码展示:
Python版本
class Solution: def hasPathSum(self , root , sum ): # write code here def preOrder(root, res): if not root: return False # 计算节点数字之和 res += root.val if not root.left and not root.right and res == sum: return True # 递归左右子树 return preOrder(root.left, res)&nbs***bsp;preOrder(root.right, res) return False if not root else preOrder(root, 0)
复杂度分析:
时间复杂度 O(N) : N 为二叉树的节点数,最差的情况递归所有节点。空间复杂度 O(1) : 常数级变量空间
算法思想二:深度优先遍历+回溯
解题思路:
1、首先,深度优点遍历来说,先写上一个回溯 if (curNode == null) { return false; },这表示递归至最深层开始回溯,至于为什么 return false 后面再讲2、每次进入函数时,将 sum 减去当前节点的权重(curNode.val),当 sum 减到零时,说明目标路径存在,另外我们的目标是到叶子节点停止,叶子节点的条件是 curNode.left == null && curNode.right == null,所以说当 if (curNode.left == null && curNode.right == null && target == 0) ,我们返回 true 表示找到目标路径
3、深度遍历的分支:对于当前节点 curNode 有两个分支,这两个分支都有可能成为目标路径,所以深度优先遍历的写法为 return dfs(curNode.left, target) || dfs(curNode.right, target);
4、现在来谈谈为什么回溯时需要返回 false,因为当 curNode 为叶子节点时,并且 sum == 0 时,我们已经返回了 true,剩下的情况就是 curNode 不是叶子节点或者路径值不为 target,所应该返回 false
图解:
代码展示:
JAVA版本
public class Solution { /** * * @param root TreeNode类 * @param sum int整型 * @return bool布尔型 */ public boolean hasPathSum (TreeNode root, int sum) { // write code here if (root == null) { return false; } // 深度优先遍历 return dfs(root, sum); } private boolean dfs(TreeNode curNode, int target) { // 目标路径不存在,开始回溯 if (curNode == null) { return false; } // 更新目标值 target -= curNode.val; // 当当前节点为叶子节点并且目标路径存在时,返回 true if (curNode.left == null && curNode.right == null && target == 0) { return true; } // 对左右分支进行 dfs return dfs(curNode.left, target) || dfs(curNode.right, target); } }
复杂度分析:
时间复杂度 O(N) : N 为二叉树的节点数,最差的情况递归所有节点。空间复杂度 O(1) :不需要额外空间