给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
示例 1:
输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示。
示例 2:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:3
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/path-sum-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
public int pathSum(TreeNode root, int targetSum) {
return pathSumI(root, targetSum);
// return pathSumII(root, targetSum);
// return pathSumIII(root, targetSum);
}
//方法三:前缀和思想,时间和空间复杂度O(N)
private int pathSumIII(TreeNode root, int targetSum) {
//key是前缀和,value是前缀和出现的次数
Map<Long, Integer> prefixMap = new HashMap<>();
//前缀和为0的一条路径,也就是如果某个节点的值就是target,它本身就是一个解
prefixMap.put(0L, 1);
return recursivePathSum(root, prefixMap, targetSum, 0L);
}
private int recursivePathSum(TreeNode root, Map<Long, Integer> prefixMap, long targetSum, long currSum) {
if (root == null) {
return 0;
}
int result = 0;
currSum += root.val;
//因为当前和为currSum,所以只要找到和为currSum - targetSum的路径即可
result += prefixMap.getOrDefault(currSum - targetSum, 0);
//更新前缀和为currSum的次数
prefixMap.put(currSum, prefixMap.getOrDefault(currSum, 0) + 1);
//递归,进入下一层
result += recursivePathSum(root.left, prefixMap, targetSum, currSum);
result += recursivePathSum(root.right, prefixMap, targetSum, currSum);
//递归结束后,为防止影响其他分支,需要去除当前节点的前缀和数量
prefixMap.put(currSum, prefixMap.get(currSum) - 1);
return result;
}
//方法二:使用BFS + DFS,时间复杂度O(N^2),空间复杂度O(N)
int count = 0;
private int pathSumII(TreeNode root, int targetSum) {
if (root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
while (size-- > 0) {
TreeNode node = queue.poll();
//当前结点为起始的满足要求的路径数量
dfs(node, targetSum, 0);
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
return count;
}
private void dfs(TreeNode node, long targetSum, long sum) {
if (node == null) {
return;
}
sum += node.val;
if (sum == targetSum) {
count++;
}
dfs(node.left, targetSum, sum);
dfs(node.right, targetSum, sum);
}
//方法一:递归,穷举所有可能,时间复杂度O(N^2),空间复杂度O(N)
//双递归,定义递归函数pathSumI来遍历二叉树所有节点,这里使用前序遍历二叉树
//在遍历过程中,定义递归函数traverse(node,targetSum)表示以任一节点node为根节点且满足路径和等于targetSum的路径总数
private int pathSumI(TreeNode root, int targetSum) {
if (root == null) {
return 0;
}
//以root为根节点且满足路径和要求的路径数量
int result = traverse(root, targetSum);
//递归遍历左右子树,求满足条件的路径数量
result += pathSumI(root.left, targetSum);
result += pathSumI(root.right, targetSum);
return result;
}
//这里需要注意,防止溢出,需要定义成long类型
private int traverse(TreeNode root, long sum) {
if (root == null) {
return 0;
}
int result = 0;
if (root.val == sum) {
result++;
}
result += traverse(root.left, sum - root.val);
result += traverse(root.right, sum - root.val);
return result;
}
}