给定N个非负整数,求解至少需要选多少个连续的数,它们的和不小于给定的整数S,特别的,若没有解,则输出0

给定N个非负整数,求解至少需要选多少个连续的数,它们的和不小于给定的整数S,特别的,若没有解,则输出0.

这是一个非常经典的应用题,常规思想就是暴力所有不同连续个数的和,满足条件的最少个数为最终答案,不管是实现还是复杂度都是很复杂的。

优化一:因为是连续的数的和,所以可以通过一个额外的数组Sum来存储前缀和,Sum[i]表示第0个数到第i个数的连续的和,那么Sum[i+k]-Sum[i]就表示第i个数起,连续k个数的和,非常方便的获取一段连续数的和,而不用每次都循环累加计算。
优化二:因为答案具有连续性,为0, 1, 2, … , N中的一个,通过二分答案的方式可以进一步降低复杂度。具体步骤为:首先假设答案为N/2,验证是否存在连续N/2个数满足条件,若满足则将答案缩小到0 1 2, … , N/2/2,否则答案在N/2/2+1, … , N这区间里,不断的二分缩小答案区间,最终得到答案。
基于队列的算法则可以将复杂度降到O(N),具体是通过维护一个受条件约束(队列里元素和小于S)的队列Que和一个整数变量tot(队列里元素的和)来实现:

step1:按数组元素顺序依次将元素添加队列Que,整型变量tot依次累加该元素值,直到tot大于等于S时停止入队操作,此时队列长度就是满足条件的备选答案;
step2:移除队首元素,整型变量tot依次减去队首元素,直到tot小于S时停止出队操作;
step3:跳转step1,直到所有数组元素依次被添加到队列,最终答案就是所有备选答案中的最小值。

//
// main.cpp
// step1
//
// Created by ljpc on 2018/9/13.
// Copyright © 2018年 ljpc. All rights reserved.
//
#include
#include
#include
#include
using namespace std;

int main(int argc, const char * argv[]) {

// 请在这里补充代码,完成本关任务
/********* Begin *********/
int n, s, x,b, a[50],sum[100];
scanf("%d %d",&n,&s);
for ( int i = 0 ; i < n ; i++ )
{
    scanf("%d",&x);
    a[i] = x ;
    b = 0;
    for ( int j = 0 ; j <= i; j ++ )
    {
        b+=a[j];
    }
    sum[i] = b ;
}
//cout << sum[1] << endl << sum[2] <<endl;
int mi = n+1;
for ( int i = 0 ; i < n ; i++ )
{
    for ( int k = 0 ; i+k < n ; k++ )
    {
        //cout << a[i] <<' ' << sum[i+k] << ' ' << sum[i];
        int y = a[i] + sum[i+k] - sum[i] ;
        /*cout << "i=" << i << "k=" << k << "y=" << y << endl;
        cout << a[i] <<' ' << sum[i+k] << ' ' << sum[i]<<endl;
        cout << " y = " << y <<endl ;// 从i,i+1 until i+k*/
    	if ( mi > k+1 && y >= s ) { mi = k+1; /*cout << a[i] <<' ' << sum[i+k] << ' ' << sum[i]<<endl;cout << "i=" << i << "k=" << k << "y=" << y << endl;*/}
    }
}
if ( mi != n+1 ) cout << mi << endl;
else cout << 0 <<endl;
/********* End *********/

return 0;

}

猜你喜欢

转载自blog.csdn.net/To_Kiss_Someone/article/details/88798217