0%

UVA11572题:唯一的雪花(滑动窗口)

今天的这道题是关于滑动窗口的题目

题目传送门

https://vjudge.net/problem/UVA-11572

题意

这道题目的题意比较简单明了,在一个长度为A的序列中选出一串没有相同元素的序列,问序列最长为几

滑动窗口+set

首先这道题可以使用滑动窗口解决,我们从序列的开头开始,使用left指针指向子序列的开头,right指针指向子序列的结尾(当然一开始他们都是指向0),然后我们将right向右移,并将right访问到的元素一一加入集合中,当我们发现集合中已经有这个元素的时候,我们就试图将left向右移来删除元素,直到没有冲突的元素后(说明left已经把这个元素给删了),我们就可以继续移动right指针了,这所有的操作都将持续到right碰到右边界。

这种操作相当于是有一个滑动的窗口在数组上滑动,所以呢我们又称这种操作叫做滑动窗口。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;

int main(){
int T;
while(cin>>T){
int n;
while(T--){
cin>>n;
int *a=new int[n+10];
set<int> s;
for(int i=0;i<n;i++)
cin>>a[i];
int left=0,right=0;
int ans=0;
while(right<n){
if(left>right)
right=left;
if(!s.count(a[right])) {
s.insert(a[right]);
right++;
ans=max(ans,right-left);
}
else{
s.erase(a[left]);
left++;
}
}
cout << ans << endl;
}
}
return 0;
}

滑动窗口+map

我们有另一种方法也可以解决这个问题——使用map,我们可以先对这个数组进行一次遍历,找到每个数字上一次出现的位置(如果没有就设置成-1),然后我们仍然使用滑动窗口的方法,只要right指向的数字上一次出现的位置在left左边(也就是在窗口外面),我们就让right继续移动,如果在里面就将left右移来删除数字,仍然是正确的方法,虽然在速度上可能并不如第一种方法,不过相差不了多远

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;

int main(){
int T;
while(cin>>T){
int n;
while(T--){
cin>>n;
int *a=new int[n+10];
int *pre=new int[n+10];
map<int,int> mp;
for(int i=0;i<n;i++) {
cin >> a[i];
if(mp.count(a[i]))
pre[i]=mp[a[i]];
else
pre[i]=-1;
mp[a[i]]=i;
}
int left=0,right=0,ans=0;
while(right<n){
if(pre[right]<left){
right++;
ans=max(ans,right-left);
}
else
left++;
}
cout << ans << endl;
}
}
return 0;
}