尺取法(窗口滑动)

目录

尺取法的用途

尺取法的思想

例题解析

题目的大意

总结


尺取法的用途

在大多数情况下,用于解决给定序列中,搜寻某个符合特定要求的子序列,比如一串数字序列,找到“连续且和为某值的最大(小)子序列”“连续且不存在重复数字的最大子序列”等等,这可以说是一系列问题了。如果用在字符串上,可能你会联想到KMP或者BF这种模式匹配的算法,其实他们有共同点。

尺取法的思想

顾名思义,像使用一把尺子一样,你用这个算法按照某个规则“量”出子序列。所以,你需要一个起点(front)和一个终点(rear)用来测量子序列。让后你通过不断的移动front和rear,进而找到你所需要的子序列(这可比枚举效率高多了)。

说到这你可能也意识到了尺取法适合用于有一定规律的序列中,或者说是连续的序列中,当然,算法并不是死板的,只要可以,你想用在哪都没问题。

例题解析

毕竟不管做什么,学习思想之后,通过练习才能融会贯通。这里我选了一道比较经典的题,用两种方式(一种用循环,一种调用STL算法)实现尺取法。

实例:Unique Snowflakes

Emily the entrepreneur has a cool businessidea: packaging and selling snowflakes. She has devised a machine that capturessnowflakes as they fall, and serializes them into a stream of snowflakes thatflow, one by one, into a package. Once the package is full, it is closed andshipped to be sold. The marketing motto for the company is “bags ofuniqueness.” To live up to the motto, every snowflake in a package must bedifferent from the others. Unfortunately, this is easier said than done,because in reality, many of the snowflakes flowing through the machine areidentical. Emily would like to know the size of the largest possible package ofunique snowflakes that can be created. The machine can start filling thepackage at any time, but once it starts, all snowflakes flowing from themachine must go into the package until the package is completed and sealed. Thepackage can be completed and sealed before all of the snowflakes have flowedout of the machine. Input The first line of input contains one integer specifyingthe number of test cases to follow. Each test case begins with a linecontaining an integer n, the number of snowflakes processed by the machine. Thefollowing n lines each contain an integer (in the range 0 to 109 , inclusive)uniquely identifying a snowflake. Two snowflakes are identified by the sameinteger if and only if they are identical. The input will contain no more thanone million total snowflakes.

 Output

For each test case output a line containingsingle integer, the maximum number of unique snowflakes that can be in apackage.

 Sample Input

1

5

1

2

3

2

1

SampleOutput

3

题目的大意

给数字序列,找到其中连续且不存在相等值的最大长度子序列。例题的序列是1、2、3、2、1。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int ves[1000010];

int main(void)
{
	ios::sync_with_stdio(false);
	int T;
	cin >> T;	//输入案例数
	while (T--) {
		memset(ves, 0, sizeof(ves));
		int M;
		cin >> M;	//输入序列共有多少个值
		for (int i = 0; i < M; i++) {
			cin >> ves[i];
		}

		int front, rear;//rear指向子序列的末尾的下一个位置
		front = 0; rear = 1;
		int count = rear - front; int Max = 1;
		while (rear != M) {
			int ptr = front;//ptr用于在子序列中遍历的操作
			while (ptr != rear) {
				if (ves[ptr] != ves[rear]) ptr++;
				else {
					count = rear - ptr;		//count用于计算每次遇见相同值时,目前子序列的最大长度
					front = ptr + 1;
					break;
				}
			}
			if (ptr == rear) count++;
			rear++;
			Max = max(count, Max);
		}

		cout << Max << endl;
	}

	return 0;
}

这种方式超时,但是思路比较清晰。运行中的模拟(有点粗糙)

(1) (2) (3)
front:0 0 0 2
rear:1 2 3 4
Max:1 2 3 3
count:1 2 3 2
序列:1 2 3 2 1

#include<iostream>
#include<cstring>
#include<set>
using namespace std;
const int N = 1000005;
int a[N];
int maxi(int a, int b)
{
	return a>b ? a : b;
}
int main()
{
	ios::sync_with_stdio(false);

	int t, n;
	set<int> s;
	cin >> t;
	while (t--)
	{
		s.clear();
		cin >> n;
		for (int i = 1; i <= n; i++)
			cin >> a[i];

		int left = 1, right = 1, num = 0;

		while (right <= n)
		{
			while (right <= n && !s.count(a[right]))
				s.insert(a[right++]);
			num = maxi(num, right - left);
			s.erase(a[left++]);
		}
		cout << num << endl;
	}
	return 0;
}

这种方式是可以AC的,思路和上面的一致。

总结

尺取法的思想并不难,效率比一般枚举高得多,而且还是适用于一类的问题,所以需要我们去掌握。当然检验掌握与否就是要靠做题,你不去做题,就算知道思想,到时候也未必能实现。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值