Leetcode刷题437. 路径总和 III

给定一个二叉树的根节点 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;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值