优选算法第四讲:前缀和模块
优选算法第四讲:前缀和模块
- 1.[模板]前缀和
- 2.【模板】二维前缀和
- 3.寻找数组的中心下标
- 4.除自身以外数组的乘积
- 5.和为k的子数组
- 6.和可被k整除的子数组
- 7.连续数组
- 8.矩阵区域和
1.[模板]前缀和
链接: link
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n = 0, q = 0;
cin >> n >> q;
vector<int> arr(n+1);//开辟一个n+1的数组
for(int i = 1; i <= n; i++) cin >> arr[i];
//创建一个前缀和数组。vector的构造会自己初始化
vector<long long> dp(n+1);
//更新前缀和数组
for(int i = 1; i<=n; i++) dp[i] = dp[i-1] + arr[i];
//直接使用前缀和数组进行返回即可
int l = 0, r = 0;
while(q--)
{
cin >> l >> r;
cout << dp[r] - dp[l-1] << endl;//直接输出结果即可
}
return 0;
}
2.【模板】二维前缀和
链接: link
3.寻找数组的中心下标
链接: link
class Solution {
public:
int pivotIndex(vector<int>& nums) {
int n = nums.size();
vector<int> f(n), g(n);
//1.分别求出前缀和、后缀和数组
for(int i = 1; i<n; i++)
f[i] = f[i-1] + nums[i-1];
for(int i = n-2; i>=0; i--)
g[i] = g[i+1] + nums[i+1];
//2.使用前缀和、后缀和数组
for(int i = 0; i<n; i++)
if(f[i] == g[i])
return i;
return -1;
}
};
4.除自身以外数组的乘积
链接: link
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n = nums.size();
vector<int> f(n), g(n);
//1.先求出f和g数组
f[0] = 1;//注意:细节问题一定要处理
g[n-1] = 1;
for(int i = 1; i<n; i++)
f[i] = f[i-1] * nums[i-1];
for(int i = n-2; i>=0; i--)
g[i] = g[i+1] * nums[i+1];
//2.使用两数组
vector<int> ret(n);
for(int i = 0; i<n; i++)
ret[i] = f[i] * g[i];
return ret;
}
};
5.和为k的子数组
链接: link
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> hash;
hash[0] = 1;
int sum = 0, ret = 0;
for(auto e : nums)
{
sum += e;//计算当前位置的前缀和
if(hash.count(sum - k)) ret += hash[sum-k];
hash[sum]++;
}
return ret;
}
};
6.和可被k整除的子数组
链接: link
class Solution {
public:
int subarraysDivByK(vector<int>& nums, int k) {
unordered_map<int, int> hash;
hash[0] = 1;//细节问题:如果nums的和可被k整除,那么也要将次数+1
int sum = 0, ret = 0;
for(auto e : nums)
{
sum += e;
int r = (sum%k + k) % k;//求余数的方法
if(hash.count(r)) ret += hash[r];//如果sum%k = 前缀和%k,那么就可以被k整除
hash[r]++;
}
return ret;
}
};
7.连续数组
链接: link
class Solution {
public:
int findMaxLength(vector<int>& nums) {
unordered_map<int, int> hash;
hash[0] = -1;
int sum = 0, ret = 0;
for(int i = 0; i<nums.size(); i++)
{
sum += nums[i] == 0 ? -1 : 1;//我们不需要将数组的0改为1,只需要在加的这个部分加-1就行了
if(hash.count(sum)) ret = max(ret, i-hash[sum]);
else hash[sum] = i;//此时存储的应该是下标
}
return ret;
}
};
8.矩阵区域和
链接: link
class Solution {
public:
vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
int m = 0, n = 0;
m = mat.size();
n = mat[0].size();
//先计算出前缀和数组
vector<vector<int>> dp(m+1, vector<int>(n+1));
for(int i = 1; i<=m; i++)
for(int j = 1; j<=n; j++)
dp[i][j] = dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+mat[i-1][j-1];
//前缀和数组的使用
vector<vector<int>> ret(m, vector<int>(n));
for(int i = 0; i<m; i++)
{
for(int j = 0; j<n; j++)
{
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
x1 = max(0, i-k) + 1;
y1 = max(0, j-k) + 1;
x2 = min(m-1, i+k) + 1;
y2 = min(n-1, j+k) + 1;
ret[i][j] = dp[x2][y2] - dp[x1-1][y2] - dp[x2][y1-1] + dp[x1-1][y1-1];
}
}
return ret;
}
};