一. 前缀和技巧
(1)前缀和
前缀和技巧适用于快速、频繁地计算一个索引区间内的元素之和。
class NumArray {
public:
vector<int> preSum; //前缀和数组
NumArray(vector<int>& nums) {
//preSum[0] = 0,便于计算累加和
preSum.resize(nums.size() + 1, 0);
for(int i = 0; i < nums.size(); i++){
preSum[i + 1] = preSum[i] + nums[i];
}
}
int sumRange(int left, int right) {
// 查询闭区间 [left, right] 的累加和
return preSum[right + 1] - preSum[left];
}
};
(2)前缀和+哈希表
前缀和数组帮你快速计算子数组的元素之和,但如果让你寻找某个符合条件的子数组,怎么办?比方说,让你在 nums
中寻找和为 target
的子数组,就算有前缀和数组的帮助,你也要写个嵌套 for 循环。但我们可以借助哈希表记录每个前缀和对应的索引,这样就能快速计算目标和为 target
的子数组了
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int len = 0;
vector<int> preSum(nums.size() + 1, 0);
for(int i = 0; i < nums.size(); i++)
preSum[i+1] = preSum[i] + (nums[i] == 0 ? -1 : 1);
// 前缀和到索引的映射,方便快速查找所需的前缀和
unordered_map<int, int> umap;
for(int i = 0; i < preSum.size(); i++){
// 如果这个前缀和还没有对应的索引,说明这个前缀和第一次出现,记录下来
if(umap.find(preSum[i]) == umap.end()) umap[preSum[i]] = i;
else len = max(len, i - umap[preSum[i]]);
}
return len;
}
};
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
vector<int>preSum(nums.size() + 1, 0);
for(int i = 0; i < nums.size(); i++)
preSum[i + 1] = preSum[i] + nums[i];
unordered_map<int, int> umap;
// 寻找 i, j 使得 (preSum[i] - preSum[j]) % k == 0 且 i - j >= 2
// (preSum[i] - preSum[j]) % k == 0 其实就是 preSum[i] % k == preSum[j] % k
for(int i = 0; i < preSum.size(); i++){
auto it = umap.find(preSum[i] % k);
if(it == umap.end()) umap[preSum[i] % k] = i;
else if ((i - it->second) >=2) return true;
}
return false;
}
};
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int ans = 0;
vector<int> preSum(nums.size() + 1, 0);
for(int i = 0; i < nums.size(); i++){
preSum[i + 1] = preSum[i] + nums[i];
}
// 寻找 i, j 使得 preSum[i] - preSum[j] == k, i > j
// nums = [1,2,3], k = 3, preSum = [0,1,3,6]
unordered_map<int, int> umap;
for(int i = 0; i < preSum.size(); i++){
if(umap.find(preSum[i] - k) != umap.end()) ans += umap[preSum[i] - k]; // 该语句必须放在前面
if(umap.find(preSum[i]) == umap.end()) umap[preSum[i]] = 1;
else umap[preSum[i]]++;
}
return ans;
}
};
class Solution {
public:
int pathSum(TreeNode* root, int targetSum) {
int ans = 0;
long pathSum = 0;
unordered_map<long, long> umap; umap[0] = 1;
traverse(root, targetSum, pathSum, umap, ans);
return ans;
}
void traverse(TreeNode* root, int& targetSum, long& pathSum, unordered_map<long, long>& umap, int& ans){
if(root == nullptr) return;
pathSum += root->val;
ans += umap[pathSum - targetSum];
umap[pathSum]++;
traverse(root->left, targetSum, pathSum, umap, ans);
traverse(root->right, targetSum, pathSum, umap, ans);
umap[pathSum]--; //这个必须放前面!!!!!!!!!!!!
pathSum -= root->val;
}
};