【数学】前缀和

一.定义

前缀和是一种常用的算法,用于快速计算数组的区间和。前缀和数组的每个元素表示原始数组中前面所有元素的和,例如,对于原始数组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(n^{3})):

 

#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(n^{2}))

#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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值