一.定义
前缀和是一种常用的算法,用于快速计算数组的区间和。前缀和数组的每个元素表示原始数组中前面所有元素的和,例如,对于原始数组a=[1,3,5,7,9],其前缀和数组为prefix=[1,4,9,16,25]。通过前缀和数组,可以在O(1)时间内计算任意区间的和,例如,区间[1,3]的和为prefix[3]-prefix[0]=16-1=15。前缀和算法的时间复杂度为O(n),其中n为原始数组的长度。
(来源于Chit GPT)
二.简单讲解
(1)创建数组(注意舍去0下标,从一开始,因为刚开始sum要-1)
sum[i]=sum[i-1]+a[i] //根据这个公式算出对应的sum数组
(2)查找a[i]~a[j]的值
即ans=sum[j]-sum[i-1] //不理解这个公式的话可以对照上一个表格看看
eg:要求a[3]~a[6]的区间和
1.若一一遍历的话就是:5+7+9+10=31;
2.用前缀和:ans=sum[6]-sum[3-1]=34-3=31;
是不是前缀和快多了
三.实战讲解
(1)题目
题目描述:有n个整数存入a数组中,现在有一个整数s,要求a[i]+a[i+1]+a[i+2]+......a[j]>=s
是否存在区间i~j之间的长度最小。若存在输出长度,不存在输出-1。
输入描述:第一行输入一个n,s分别表示有n个整数和正整数s
第二行输入n个整数
输出描述:输出最小长度,或-1
样例输入:
7 6
1 1 1 1 1 5 2样例输出:
2
(a[6]+a[7]>=6,最后两个数符合答案,长度为2。
a[1]+a[2]+...+a[6]>=6,但长度为6,不佳,舍去。)
(2)思路 :
因为是有序数列,所以我们不能用贪心来排列,这样会打乱顺序
所以我们只能暴力枚举找最小长度,但枚举的过程中,在求区间和时用前缀和可以减少许多时间复杂度。
(3)暴力解法(O()):
#include<bits/stdc++.h>
using namespace std;
int a[1001];
int main(){
int len=1e6;
int n,s;
cin>>n>>s;
for(int i=1;i<=n;i++) cin>>a[i];
//查找
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int sum=0;
//前缀和的精髓就是省去这次遍历
for(int k=i;k<=j;k++) sum+=a[k];
if(sum>=s) len=min(len,j-i+1);
}
}
cout<<len<<endl;
return 0;
}
(4)前缀和解法(O())
#include<bits/stdc++.h>
using namespace std;
int a[1001],sum[1001];
int main(){
int len=1e6;
int n,s;
cin>>n>>s;
for(int i=1;i<=n;i++){
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
//查找
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(sum[j]-sum[i-1]>=s) len=min(len,j-i+1);
}
}
cout<<len<<endl;
return 0;
}