目前见过的题目,都是前缀和结合其它的方法一起使用:用于求取一段连续路径的和(最大值/最小值/目标出现次数)
需要注意的是,前缀和的判定方法是node2.val-node1.val == target,不要搞错顺序
文章目录
1.路径之和III
在数据结构 - 二叉树记录过,此处单独拿出来。
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
符合求取连续路径的和的特点。
使用DFS+前缀和的思路。DFS的一个明显好处是,每条正在搜索的路径一定符合题目中对路径的要求。将当前路径节点的前缀和记录到path备用。
class Solution {
int count = 0;
List<Long> path = new LinkedList<>(); // 记录当前路径上的前缀和
public int pathSum(TreeNode root, int targetSum) {
// 加入空节点,方便计算路径包括根节点的值
path.add(0L);
// 执行搜索
dfs(root, targetSum);
return count;
}
private void dfs(TreeNode node, int targetSum) {
// 递归出口
if (node == null) {
return;
}
// 计算当前位置的前缀和
long tempPrefixSum = path.get(path.size() - 1) + node.val;
// 寻找当前路径是否有符合条件的路径
for (int i = 0; i < path.size(); i++) {
if (tempPrefixSum - path.get(i) == targetSum) {
count++;
}
}
path.add(tempPrefixSum);
dfs(node.left, targetSum);
dfs(node.right, targetSum);
path.remove(path.size() - 1);
}
}
2.和为 K 的子数组
给你一个整数数组 nums 和一个整数 k ,请你统计并返回该数组中和为 k 的连续子数组的个数
符合求取连续路径的和
class Solution {
public int subarraySum(int[] nums, int k) {
// 求前缀和
for (int i = 1; i < nums.length; i++) {
nums[i] += nums[i - 1];
}
// 统计个数
int count = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == k) {
count++;
}
for (int j = 0; j < i; j++) {
if (nums[i] - nums[j] == k) {
count++;
}
}
}
return count;
}
}
- 这里如果需要获得具体的序列,在保证没有负数的前提下,可以使用滑动窗口解决
- 如果有负数,不能用滑动窗口解(因为不能保证左指针右移使得和变小)
class Solution:
def FindContinuousSequence(self, tsum):
if tsum <= 1:
return []
start, end = 0, 1
summary = 0
res = []
while (start <= end and end <= (tsum // 2 + 2)):
if summary == tsum:
res.append([i for i in range(max(start, 1), end)])
summary += end
end += 1
elif summary < tsum:
summary += end
end += 1
else:
summary -= start
start += 1
return res