尺取法枚举区间

尺取法也叫(追逐法 、 two pointer) ,顾名思义,像尺子一样,一块一块的截取。尺取法比直接暴力枚举区间效率高很多,尤其是数据量大的时候,所以说尺取法是一种高效的枚举区间的方法,是一种技巧。用尺取法来优化,可以使复杂度降为O(n)。是不是解释的有点让人纳闷~。。没关系,下面我们通过这个题目来体会尺取法的魅力。

题目内容
  给定长度为n的数列整数a0,a1,a2,a3 … an-1以及整数S。求出综合不小于S的连续子序列的长度的最小值。如果解不存在,则输出0。

这里我们拿第一组测试数据举例子,即 n=10, S = 15, a = {5,1,3,5,10,7,4,9,2,8}

尺取法的整个过程分为4部:

1.初始化左右端点

2.不断扩大右端点,直到满足条件

3.如果第二步中无法满足条件,则终止,否则更新结果

4.将左端点扩大1,然后回到第二步

过程分析:
首先,序列都是正数,如果一个区间其和大于等于S了,那么不需要在向后推进右端点了,因为其和也肯定大于等于S但长度更长,所以,当区间和小于S时右端点向右移动,和大于等于S时,左端点向右移动以进一步找到最短的区间,如果右端点移动到区间末尾其和还不大于等于S,结束区间的枚举。

最后,再给一个尺取法的定义以便更好理解:返回的推进区间开头和结尾,求满足条件的最小区间的方法称为尺取法。

#include
using namespace std;
#define N 10
#define S 15
int solve(int a[])
{
	int res=N+1,sum=0,r=0,l=0; 
	while(1) {
		while(sum < S && r < N) {
			sum+=a[r++]; 
		}
		if(sum < S) {
			return res;
		}
		res=min(res,(r-l));
		sum-=a[l];
		l++;
	}
}
int main()
{
	int a[N]={5,1,3,5,10,7,4,9,2,8};
	int res=solve(a);
	printf("%d\n",res);
}

参考博客:http://blog.chinaunix.net/uid-24922718-id-4848418.html
https://blog.csdn.net/lxt_lucia/article/details/81091597

你可能感兴趣的:(尺取法枚举区间)