#面试题#前伸后缩法


题目:给定长度为n的整数数列:a0,a1,..,an-1,以及整数S。这个数列会有连续的子序列的整数总和大于S的,求这些数列中,最小的长度。

 

如果数列中有正有负,则直接用 O(n^2)的算法。

 

现在讨论 数列中全为非负数的情况:

令i, j 都指向 数列的第一个元素,之后循环执行以下步骤:

1. j++ 直到 a[i] + .... + a[j] > S;

2. i++ 直到 a[i] + ..... + a[j] <= S, 同时更新最小长度。(这里注意i <= j)

 

之所以可以这么做的理论证明是:

1.如果 a[i] + .... + a[j] > S, 那么显然不用再枚举 a[i] + .... + a[j+1] 的情况,也同样不用枚举a[i-1] + ..... + a[j] 的情况。而只需要枚举a[i+1] + ...... + a[j]的情况(因此可以“后缩”)。

2.如果 a[i] + .... + a[j] <= S, 那么 a[i+1] + .... + a[j] 显然也是 <= S的,不满足情况,所以也无需枚举。(因此需要“前伸”)。

 

代码如下:

#include
   
   
    
     
using namespace std;
int main() {
    int a[100], i = 0, j = 0;
    int s;
    cin >> s;
    while (cin >> a[i++]) {
    }
    int n = i - 1;
    int sum = 0;
    int min = n;
    for (i = 0, j = 0; i < n && j < n; ) {
        while (sum <= s && j < n) {
            sum += a[j++];
        }
        while (sum > s && i < n && i <= j) {
            cout << i+1 << ":" << j << endl;
            if (j - i + 1 < min) min = j - i;
            sum -= a[i++];
        }
    }
    cout << min << endl;
    return 0;
}
   
   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值