001 DP34 【模板】前缀和
题目描述
解题思路
代码实现
#include <iostream>
#include <vector>
using namespace std;
int main() {
//1、读取数据
int n = 0, q = 0;
cin >> n >> q;
vector<int> arr(n+1, 0);
for(int i = 1; i <= n; ++i)
{
cin >> arr[i];
}
//2、预处理出前缀和数组
vector<long long> dp(n+1, 0); //long long防止求和时溢出
for(int i = 1; i <=n; ++i)
{
dp[i] = dp[i-1] + arr[i];
}
//3、使用前缀和数组求解
int l = 0, r = 0;
while(q--)
{
cin >> l >> r;
cout << dp[r] - dp[l-1] << endl;
}
return 0;
}
002 DP35 【模板】二维前缀和
题目描述
解题思路
代码实现
#include <iostream>
#include <vector>
using namespace std;
int main() {
//1、读入数据
int n = 0, m = 0, q = 0;
cin >> n >> m >> q;
vector<vector<int>> arr(n+1, vector<int>(m+1));
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
{
cin >> arr[i][j];
}
}
//2、预处理得到前缀矩阵
vector<vector<long long>> dp(n+1, vector<long long>(m+1));
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
{
dp[i][j] = dp[i-1][j] + dp[i][j-1] + arr[i][j] - dp[i-1][j-1];
}
}
//3、利用前缀矩阵计算结果
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
while(q--)
{
cin >> x1 >> y1 >> x2 >> y2;
cout << dp[x2][y2] - dp[x1-1][y2] - dp[x2][y1-1] + dp[x1-1][y1-1] << endl;
}
return 0;
}
// 64 位输出请用 printf("%lld")
003 寻找数组的中心下标
题目描述
解题思路
代码实现
// class Solution {
// public:
// int pivotIndex(vector<int>& nums) {
// //优化
// if(nums.size() == 1) return 0;
// int n = nums.size();
// int tmp = 0;
// //定义预处理数组1,2
// //dp1,dp2开n+2个大小,为了防止左右边界越界
// vector<int> dp1(n + 2,0);
// for(int i = 0; i < n; ++i)
// {
// dp1[i + 1] = nums[i] + dp1[i];
// }
// vector<int> dp2(n + 2,0);
// for(int i = n-1; i >= 0; --i)
// {
// dp2[i + 1] = nums[i] + dp2[i + 2];
// }
// //利用预处理数组求解结果
// int dest = 2;
// for(int cur = 1; cur <= n; )
// {
// if(dp1[cur - 1] == dp2[dest]) return cur - 1;
// ++dest;
// ++cur;
// }
// return -1;
// }
// };
class Solution {
public:
int pivotIndex(vector<int>& nums) {
int n = nums.size();
//1、预处理前缀和和后缀和数组
//Notice:f[i]:表示nums数组中【0,i-1】区间内所有元素之和
vector<int> f(n, 0), g(n, 0);
for(int i = 1; i <= n-1; ++i)
{
f[i] = f[i-1] + nums[i-1];
}
//Notice:g[i]:表示nums数组中【i+1,n-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;
}
};
004 除自生以外数组的乘积
题目描述
解题思路
代码实现
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n = nums.size();
//1、预处理前缀积和后缀积
vector<int> f(n, 1), 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、利用前缀积和后缀积计算最终结果
vector<int> answer;
for(int i = 0; i < n; ++i)
{
answer.push_back(f[i]*g[i]);
}
return answer;
}
};
005 和为k的子数组
题目描述
解题思路
代码实现
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> hash; //统计前缀和出现的次数
//数组中和为k的子数组个数-> 数组中[0,i]区间内,有多少个前缀个等于sum[i] - k
int sum = 0;
int ret = 0;
hash[0] = 1;
for(auto e : nums)
{
sum += e; //计算前缀和
if(hash.count(sum - k)) ret += hash[sum - k]; //统计前缀个等于sum[i] - k的个数
hash[sum]++; //将前缀和加入到hash表
}
return ret;
}
};
006 和可被k整除的子数组
题目描述
解题思路
代码实现
class Solution {
public:
int subarraysDivByK(vector<int>& nums, int k) {
unordered_map<int, int> hash;
//nums中元素之和可被k整除的非空子数目的数目->
//在[0, i - 1]区间内,计算有多少前缀和除以k的余数(即前缀和 % k)
//等于(sum % k + k) % k
int ret = 0;
int sum = 0;
hash[0 % k] = 1; //0这个数的余数
for(auto e : nums)
{
sum += e; //计算前缀和
int r = (sum % k + k) % k; //修正后的余数
//统计hash表中有多少前缀和除以k的修正后的余数(即前缀和 % k)
//等于(sum % k + k) % k
if(hash.count(r)) ret += hash[r];
hash[r]++;
}
return ret;
}
};
007 连续数组
题目描述
解题思路
代码实现
class Solution {
public:
int findMaxLength(vector<int>& nums) {
unordered_map<int, int> hash; //用于统计区间下标
int sum = 0;
int ret = 0;
hash[0] = -1; //前缀和为0时,所对应的索引为-1;
for(int i = 0; i < nums.size(); ++i)
{
sum = sum + (nums[i] == 0? -1 : 1); //将0->-1, 计算前缀和
//检查hash表中,在[0, i-1]区间中,是否存以i位置为结尾的前缀和为sum;
//若存在,则计算区间
if(hash.count(sum))
ret = max(ret, i - hash[sum]);
else
hash[sum] = i; //hash表中不存在前缀和时,才将前缀和和索引,
//保存到hash表中,相同得前缀和,我们保存的是前一个
}
return ret;
}
};