携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情
前言
- leetcode hot100,是大厂面试高频题,也是必刷算法题。精选了100道LeetCode上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,按照官方说的,熟练掌握这 100 道题,就具备了代码世界通行的基本能力。
leetcode437题(路径总和 III)
本文来讲hot100第437题,路径总和,本题题目是中等题目,也是典型的前缀和应用,与560题很像。
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
示例:
输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示。
输入: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出: 3
提示:
- 二叉树的节点个数的范围是
[0,1000] -109 <= Node.val <= 109-1000 <= targetSum <= 1000
分析
- 求二叉树里节点值之和等于targetSum的路径的数目,简单的来说就是看整个树上有多少条“路径”的和等于targetSum
- 从下面的例图也可以看出来,“路径”的方向是向下的,可以左节点也可以右节点。
思路
暴力法
- 求所有从根节点到叶子节点的路径,存储下来,然后我们再针对每条路径双指针匹配路径等于targetSum的区间。时间复杂度很高,很可能会超时
前缀和
- 看到路径会想起来之前我们560题(和为k的子数组)讲过前缀和,前缀和是从第0项到当前位置的数(nums[i])的和,也是在数组中求路径和的应用。
- 前缀和对于本题的作用,题目要求的是找出路径和等于给定数值的路径总数, 而:两节点间的路径和 = 两节点的前缀和之差
- 理解了第一点路径和之差,可以考虑2点
- 存储key是“键为presum的前缀和”,value是“键为presum的前缀和”的值,这里我们加一
- 考虑到边界情况和后续的迭代,初始化前缀和是{0:1}
- 由于路径是向下的,所以是先左子节点 再判断右子节点
代码
let ans = 0, map = new Map()
const dfs = (node, presum = 0) => {
if (!node) {
return 0
}
map.set(presum, (map.get(presum) || 0 ) + 1)
// 当前前缀和为之前的前缀和加当前的节点值
const target = presum + node.val
// 查找匹配的前缀和数量并加到ans
ans += (map.get(target-targetSum) || 0)
dfs(node.left, target)
dfs(node.right, target)
// 回溯,撤销
map.set(presum, map.get(presum) - 1)
}
dfs(root)
return ans;
结语
- 本题也是前缀和的应用,只要理解了前缀和的公式还有为什么我们匹配target - targetSum对应的前缀和,就可以很容易的做出来了,做完此题可以去做560题。