前缀和
1.1 定义
前缀和
就是从位置1到位置i这个区间内的所有的数字之和。不明白请看下面的例子。前缀和
分为一维前缀和
和二维前缀和
。
1.2 一维前缀和
- 我们先给出一个数组
src[6]={1,2,3,4,5,6}
- 这个数列的前缀和
prefixSum[6]
prefixSum[0]=src[0]=1
prefixSum[1]=src[0]+src[1]=3
prefixSum[2]=src[0]+src[1]+src[2]=6
prefixSum[3]=src[0]+src[1]+src[2]+src[3]=10
prefixSum[4]=src[0]+src[1]+src[2]+src[3]+src[4]=15
prefixSum[5]=src[0]+src[1]+src[2]+src[3]+src[4]+src[5]=21
由此得出结论:prefixSum[i]=prefixSum[i-1]+src[i]
代码理解
for (int i = 0; i < n; i ++ ){
cin >> src[i];
if(i == 0) prefixSum[i] = src[0];
prefixSum[i] = prefixSum[i - 1] + src[i];
}
1.3 二维前缀和
分为四种情况:
- i==0 ,只有一个直接赋值即可:prefixSum[0, 0] = src[0, 0]。
- i==0,最左边的一排,图中黄色部分,prefixSum[0, j] = prefixSum[0, j-1] + src[0, j];
- j==0,最上面一排,途中红色部分,prefixSum[i, o] = prefixSum[i-1, 0] + src[i, 0];
- i!=0 || j!=0,图中绿色部分,prefixSum[i][j] = prefixSum[i - 1][j] + prefixSum[i][j - 1] + src[i][j] - prefixSum[i - 1][j - 1];
我们具体讲第四步:如图所示。54=33+21+12-1
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> twoDimen(vector<vector<int>> src) {
vector<vector<int>> prefixSum(src.size(),vector<int>(src[0].size()));
for (int i = 0; i < src.size(); i++) {
for (int j = 0; j < src[0].size(); j++) {
if (i == 0 && j == 0) {//第0个,最左上角
prefixSum[i][j] = src[i][j];
} else if (i == 0) {//第一行,最顶部一行
prefixSum[i][j] = prefixSum[i][j - 1] + src[i][j];
} else if (j == 0) {//第一列,最左边一列
prefixSum[i][j] = prefixSum[i - 1][j] + src[i][j];
} else {//其他
prefixSum[i][j] = prefixSum[i - 1][j] + prefixSum[i][j - 1] + src[i][j] - prefixSum[i - 1][j - 1];
}
}
}
return prefixSum;
}
int main() {
vector<vector<int>> src={{0,1,2},{5,6,7},{10,11,12}};//定义一个3*3的矩阵
vector<vector<int>> prefixSum;//二维前缀和矩阵
for (auto iter: twoDimen(src)){
for (auto it:iter)
cout << it << " ";
cout << endl;
}
return 0;
}
1.4 前缀和的应用
- 优势:可以快速得到某一个区间的区间总和。
例题
输入n个数的数列,所有相邻m数的和有n-m+1个,求其中的最小值。
比如:数组为:[10, 4, 1, 5, 5, 2]
m为:3
结果为:10
#include <iostream>
#include <vector>
using namespace std;
int minSum(vector<int> src , int m) {
if (m <= 0) {
return 0;
}
vector<int> prefixSum(src.size());
for (int i = 0; i < prefixSum.size(); ++i) {
if (i == 0) {
prefixSum[i] = src[i];
} else {
prefixSum[i] = prefixSum[i - 1] + src[i];
}
}
//first是第一个三个数之和 prefixSum数组中的第一个值
//second=prefixSum[3]-prefixSum[0]
int first = prefixSum[m - 1], result = first;
for (int i = m; i < prefixSum.size(); ++i) {
//第(i+1)位置的前缀和-(i-m+1)的前缀和 后续三个数的和
int current = prefixSum[i] - prefixSum[i - m];
result = current > result ? result : current;
}
return result;
}
int main() {
vector<int> src={10,4,1,5,5,2};
int m;
cin >> m;
cout << minSum(src,m) << endl;
}