前缀和
剑指 Offer II 010. 和为 k 的子数组
简单前缀和
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int res = 0;
partial_sum(nums.begin(), nums.end(), nums.begin());
unordered_map<int,int> hash;
hash[0] = 1;
for(auto a : nums){
res+=hash[a-k];
hash[a]++;
}
return res;
}
};
剑指 Offer II 011. 0 和 1 个数相同的子数组
由于「00 和 11 的数量相同」等价于「11 的数量减去 00 的数量等于 00」,我们可以将数组中的 00 视作 -1−1,则原问题转换成「求最长的连续子数组,其元素和为 00」。
hash[0]=-1,因为当前缀和为零时,代表前面所有的元素都是子集,应该是i+1的长度。
- 使用一个tmp来进行0到-1的转换。
- 使用哈希表来存储前缀和以及最小下标
当哈希表中存在当前前缀和时,说明这一段的0和1数量相同,长度为i-hash[psum]
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int psum = 0, maxlen = 0, n = nums.size();
unordered_map<int,int> hash;
hash[0] = -1;
for(int i = 0; i < n; i++){
int tmp = nums[i]==0? -1:1;
psum += tmp;
if(hash.count(psum)) {
maxlen = max(maxlen, i-hash[psum]);
} else {
hash[psum] = i;
}
}
return maxlen;
}
};
剑指 Offer II 012. 左右两边子数组的和相等
注意判断边界条件
- 根据2*psum[i-1]+nums[i] = total这个公式来确定
尽量不要使用partial_sum来计算前缀和,直接在for循环里面累加就行了
class Solution {
public:
int pivotIndex(vector<int> &nums) {
int total = accumulate(nums.begin(), nums.end(), 0);
int sum = 0;
for (int i = 0; i < nums.size(); ++i) {
if (2 * sum + nums[i] == total) {
return i;
}
sum += nums[i];
}
return -1;
}
};
剑指 Offer II 013. 二维子矩阵的和
前缀和矩阵
- 先使用动态规划求矩阵的前缀和
- 然后用前缀和然会子矩阵的和
但是真的不能粗心大意
class NumMatrix {
private:
vector<vector<int>> matrixsum;
public:
NumMatrix(vector<vector<int>>& matrix) {
int n = matrix.size(), m = matrix[0].size();
vector<int> tmp(matrix[0].size()+1);
matrixsum.resize(matrix.size()+1, tmp);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
matrixsum[i][j] = matrixsum[i-1][j]+matrixsum[i][j-1]-matrixsum[i-1][j-1]+matrix[i-1][j-1];
}
}
}
int sumRegion(int row1, int col1, int row2, int col2) {
return matrixsum[row2+1][col2+1] - matrixsum[row1][col2+1]-matrixsum[row2+1][col1]+matrixsum[row1][col1];
}
};