基础算法题之求区间最大和(前缀和+双指针)

怎样求出区间和?

可以从l到r循环一遍,累加。

但这样的时间复杂度为O(r-l+1)。

如此高的时间复杂度显然是不能接受的。

我们采用前缀和进行优化。

什么是前缀和?

前缀和的第i项表示:从数列的第一项一直加到第i项的和。

sum[]表示前缀和数组,用x表示我们每一个输入的值。

显然sum[i]=sum[i-1]+x

举个栗子,对于以下数列:

原数列: 3,4,1,0,9

前缀和: 3,7,8,8,17

前缀和有什么用?

利用前缀和我们就可以在O(1)时间内处理出区间和。

对于L到R的区间和,前缀和数组为sum,原数组为a,则有:

sum[l-1]=a[1]+a[2]+...+a[l-1];

sum[r]=a[1]+a[2]+...+a[l-1]+a[l]+...+a[r];

sum[r]-sum[l-1]=a[1]-a[1]+a[2]-a[2]+...+a[l-1]-a[l-1]+a[l]+a[l+1]+...+a[r];

sum[r]-sum[l-1]=a[l]+...a[r];

那么sum[r]-sum[l-1]即为我们要求的区间和

可以感性理解一下。


怎么求出题目答案?

最容易想到的方法就是暴力枚举端点:

for(int i=1;i<=n;i++)
{
	for(int j=i+1;j<=n;j++)
	{
		...
	}
}
	

但显而易见,这绝对会超时。

我们采取双指针优化。

定义两个指针指向区间两个端点,初始时都为一。

只要当前区间和超过了m,就让左端点加一。

只要当前区间和大于上次区间和,就更新答案以及答案区间。

#include<cstdio>
using namespace std;
int n,m,x;
long long sum[4000005];
//前缀和数组
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        sum[i]=sum[i-1]+x;
        //预处理前缀和
    }
    long long ans=-1;
    //ans是最大值,所以一开始先赋值为-1,方便判断
    int l=1,r=1,ansl,ansr;
    //l,r为两个指针,开始都指向1
    //ansl,ansr为最终答案
    while(r<=n)
    {
        //防止越界
        while(sum[r]-sum[l-1]>m&&l<r)
            l++;
        //sum[r]-sum[l-1]表示l到r的区间和
        //大于m就无效,左端点加一
        //要判断l<r因为防止越界
        if(sum[r]-sum[l-1]>ans)
        {
            ans=sum[r]-sum[l-1];
            ansl=l,ansr=r;
            //更新答案
        }
        r++;
    }
    printf("%d %d %lld",ansl,ansr,ans);
    return 0;
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值