尺取法
当我们需要在给定的一些数中,找到一个最短的区间,使得区间里的每一个元素的和大于或者等于给定的一个值。
一般的想法是开两个循环,然后暴力枚举区间的起点和终点。
但是这样时间复杂度太高了,可以使用尺取法来解决这个问题。
核心思想
设置两个指针,一个左指针,一个右指针。一开始两个指针都指向数组的初始位置,然后右指针一直向右滑动,直到两个指针所确定的区间的和值大于或者等于给定的值。再把左指针一直向右滑动直到两个指针确定的区间的和值小于给定的值,此时的情况是左指针向右移动一次,两个指针所确定的区间的和值刚好小于给定的值。那么加上左指针左边的一个数就大于或者等于给定的值,此时记录下区间的长度。
然后再一直循环上面的操作,直到右指针滑到数组的最右边。
#include<stdio.h>
#define N 100000
int a[N+5];
int Min(int a, int b)
{
return a < b ? a : b;
}
int cal(int a[], int len, int s)
{
int L, R, cnt = 0, ans = 99999999, sum = 0;
L = R = 0;
while(R < len)
{
while(R < len && sum < s)
{
sum += a[R];
R++;//右指针向右移
cnt++;
}
while(sum >= s)
{
sum -= a[L];
L++;//左指针向右移
cnt--;
}
ans =Min(ans, cnt+1);
}
return ans;
}
int main()
{
int t, n, s, sum;
scanf("%d", &t);
while(t--)
{
sum = 0;
scanf("%d %d", &n, &s);
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
sum += a[i];
}
if(sum < s) printf("0\n");
else printf("%d\n", cal(a, n, s));
}
return 0;
}