滑动窗口—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表示没有这个元素。

itwolf

原文地址:https://www.cnblogs.com/BeautifulWater/p/14634760.html