题目大意
给定有n个正整数构成的序列和整数S,求长度最短的连续序列,使他们的和等于S
分析
首先想到的方法就是暴力枚举,,枚举起点和终点
for (int i = 0; i < n; i++)
for (int j = i; j < n; j++)
{
int sum = 0;
for (int k = i; k <= j; k++)
sum = sum + q[k];
if (sum >= m)
ans = min(ans, j - i + 1);
}
暴力的复杂较高,我们使用前缀和的方式降低复杂度令sum(i)=P1+P2+………Pi
sum[0] = 0;
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + q[i];
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= n; j++)
if (sum[j] - sum[i] >= m)
ans = min(ans, j - i);
}
对于一些数据量较大的情况复杂度还是很大,我们再次尝试优化,只要枚举起点和终点就一定无法降维,我们另谋他路.尝试只枚举终点,或者只枚举起点。
我们试一试枚举终点,对于终点j说我们要找到最小的i,i应该满足什么条件呢 qj-s>=qi,在满足此条件的情况下寻找最大的j,因为是正整数序列,所以S数组一定是递增的。我们可以使用二分查找
核心代码
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + q[i];
int ans = n + 1;
for (int j = 1; i < n; i++) {
int i = lower_bound(sum, sum + j, sum[j] - s) - sum;
if (i > 0) ans = min(ans, j - i + 1);
}
关于二分查找,详见大佬lower_bound和upper_bound
还有一种不用二分查找的方法,因为sum是递增的,j是递增的那么i也一定是递增的
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + q[i];
int i = 1,ans=n+1;
for (int j = 1; j <= n; j++)
{
if (sum[j] - m <= sum[i-1]) continue;
while (sum[j] - sum[i] >= m) i++;
ans = min(ans, j - i + 1);
}