输入一个长度为n(n<=1e6)的序列A,找到一个尽量长的连续子序列AL~AR,使得该序列中没有相同元素。输出最大长度。
核心是:
对数据处理类似与一个队列的结构,队头front,队尾rear,两个都可以不断增加,比如rear增加1,那么为了保证同一个元素不在队列里出现两次,可能会出队一些元素。
或者可以这么解释,对于每一个值x,记录前一个值x出现的位置last[x],所以考虑x进入序列时,last[x]及以前的元素不得考虑。
具体实现:
数据结构的选择有很多种,不管是用map还是set还是自己定义的结构体都是可以的。
我自己写的稍微麻烦点,离散化+队列处理。
离散化:先排序,然后用存储每个数值的映射值,o(nlogn)。其实这个作法相当于用map作为存储结构。
用set是很自然的想法,因为扫描的顺序是从左往右,所有set只用记录每个元素是否出现即可。
不管是枚举rear所在位置[0,n)还是front所在位置[0,n)都是可以的
/**==========================================
* This is a solution for ACM/ICPC problem
*
* @source£º
* @type:
* @author: wust_ysk
* @blog: http://blog.csdn.net/yskyskyer123
* @email: 2530094312@qq.com
*===========================================*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define REP(i,n) for(int i=0 ;i<(n) ;i++)
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn= 1000000 ;
struct Node
{
int ind,x,y;
bool operator<(const Node b)const
{
return ind<b.ind;
}
}a[maxn+4];
bool cmp(Node c,Node b)
{
return c.x<b.x;
}
int n;
struct MyQueue
{
int front,rear;
bool vis[maxn+4];
void clear()
{
front=rear=0;
memset(vis,0,n*sizeof vis[0]);
}
int size()
{
return rear-front;
}
void push(int y)
{
if(!vis[y])
{
rear++;
vis[y]=1;
return;
}
while(a[front].y!=y )
{
vis[a[front].y]=0;
front++;
}
front++;
rear++;
}
}Q;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
REP(i,n)
{
scanf("%d",&a[i].x);
a[i].ind=i;
}
sort(a,a+n,cmp);
REP(i,n)
{
a[i].y=i;
int t=i;
while(i+1<n&&a[i+1].x==a[i].x)
{
a[++i].y=t;
}
}
sort(a,a+n);
Q.clear();
int ans=0;
REP(i,n)
{
int y=a[i].y;
Q.push(y);
ans=max(ans,Q.size());
}
printf("%d\n",ans);
}
return 0;
}