题目:给定长度为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;
}