题目:
输入一个长度为n(n<=1e6)的序列A,找到一个尽量长的连续子序列AL~AR,使得该序列中没有相同元素。输出最大长度。
分析与解答
对于这种子序列问题我们采用模拟的方法
方法一:利用set
1.如果有一个序列的元素没出现过,就把元素存到set里,
2.如果出现过,说明a[r+1]在子序列a[l]——a[r]出现过,那此时就不断地删去l,直到r增大到n
注意这里并不是说我删掉最左边的,那么l+1到r+1就是一个新的满足条件的最长子序列,比如1,2,3,4,5,4,6,7,8,9
这里只不过是把所有可能情况走一遍
左边走,右边停着
右边走,左边停着
决定谁停的条件,就是r+1是不是曾经出现过,用set的count函数非常方便,而且set也有插入和删除,左边往前走,删除,右边往前走,插入
3.注意保存并更新最大序列个数
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=1000000+5;
int a[maxn];int main(){int t,n;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=0;i<n;++i) scanf("%d",&a[i]);set<int> s;int l=0,r=0,ans=0;while(r<n){while(r<n&&!s.count(a[r])) s.insert(a[r++]);ans=max(ans,r-l);s.erase(a[l++]);}printf("%d\n",ans);}
}
方法二
利用map
1.构造数组last[i],存的元素是下标i的上一个相同元素的下标
如果这个元素第一次出现,那么last[i]=-1
2.map分别存的是值和下标,cur[值]=下标
3.同样是有一个l,last[r]与l进行比较,如果小于,说明此时可以继续扩展
4.虽然麻烦,但是与抽屉原理异曲同工之妙
#include<stdio>
#include<map>using namespace std;const int maxn=1000000+5;
int a[maxn],last[maxn];
map<int,int>cur;int main(){int t,n;scanf("%d",&t);while(t--){scanf("%d",&n);cur.clear();for(int i=0;i<n;++i){scanf("%d",&a[i]);if(!=cur.count(a[i])) last[i]=-1;else last[i]=cur[a[i]];cur[a[i]]=i;//存a[i]的下标}int l=0,r=0,ans=0;while(r<n){while(r<n&&last[r]<l) r++;ans=max(ans,r-l);l++;}printf("%d\n",ans);}
}