滑动窗口—UVA11572 唯一的雪花 Unique Snowflakes
UVA11572 唯一的雪花 Unique Snowflakes
滑动窗口
做法一(加入实时判断):
- 如果说新读入的元素并没有在已知的窗口内存在的话,那不妨将这个新读入的元素纳入到窗口中,同时需要对这个新元素的个数进行记录。
- 集合的计数:集合名.count(所要查找的元素)
- 集合的添加:集合名.insert(所要加入的元素)
- 如果说新读入的元素有在已知的窗口内存在的话,那需要将窗口左端的元素不断弹出,直至没有重复的元素。
- 由于只有一个元素,可以直接考虑用set,而不需要用到map,set的话删除时set名.erase(所要删掉的内容)
#include<iostream>
#include<stdio.h>
#include<set>
using namespace std;
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
set<int > nums;
cin>>n;
int a[n+1];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int l=0,r=0;
int ans=0;
while(r<n)
{
while(r<n&&!nums.count(a[r]))
{
nums.insert(a[r++]);//先添加了a[r],然后在r++
}
ans=max(ans,r-l); //注意每一次的r是窗口内右端的后一个
nums.erase(a[l++]);//a[l]先退群,然后再l++
}
cout<<ans<<endl;
}
return 0;
}
做法二(记录上一个相同元素的位置)
- 用一个数组last(数组a用来记录数列中所有的元素)
- 比如last[k]表示的是第k个位置上的元素a[k]的上一个与a[k]相同的元素的位置。
- last[k]>=l表示的是这个元素的上一个相同元素的位置大于窗口的左端点。也就是说在纳入新元素后,窗口内部是存在两个相同的元素。这时需要不断地提高l的值(把窗口的左端点不断向右拉),直至last[k]<l;
- 需要另设一个数组cur来实时更新最后一个A[I]元素的位置,并将更新前的cur扔给last来实现上一个相同元素的位置的记录。
- 直接在读入的过程中完成last数组的记录
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<set>
#include<map>
using namespace std;
int main()
{
int T;
cin>>T;
map <int,int > cur;//其实就是数组
while(T--)
{
int n;
cin>>n;
int a[n+1];
int last[n+1];
for(int i=0;i<n;i++)
{
cin>>a[i];
if(!cur.count(a[i]))last[a[i]]=-1;
else last[a[i]]=cur[a[i]];
cur[a[i]]=i;
}
int l=0,r=0,ans=0;
while(r<n)
{
while(r<n&&last[a[r]]<l)r++;
ans=max(ans,r-l);
l++;
}
cout<<ans<<endl;
}
return 0;
}
做法三(双端队列deque模拟)
其他
map中count方法
- 只返回01,表示有无
map和set两种容器的底层结构都是红黑树,所以容器中不会出现相同的元素,因此count()的结果只能为0和1,可以以此来判断键值元素是否存在(当然也可以使用find()方法判断键值是否存在)。
拿map<key,value>举例,find()方法返回值是一个迭代器,成功返回迭代器指向要查找的元素,失败返回的迭代器指向end。count()方法返回值是一个整数,1表示有这个元素,0表示没有这个元素。