我的翻译
题目描述
t t t 组数据( 1 ≤ t ≤ 1 0 4 1\le t\le10^4 1≤t≤104)。
每组数据,给定 n n n( 1 ≤ n ≤ 2 ⋅ 1 0 5 1\le n\le2\cdot10^5 1≤n≤2⋅105)和序列 a = [ a 1 , a 2 , … , a n ] a=[a_1,a_2,\dots,a_n] a=[a1,a2,…,an]( 1 ≤ a i ≤ n 1\le a_i\le n 1≤ai≤n),需要删除 a a a的一个前缀,使剩下的数不重复。
找出要删除的最小前缀,输出它的长度。
样例解释
删除最小前缀后,剩下的序列分别是:
-
[ 1 , 4 , 3 ] [1,4,3] [1,4,3]
-
[ 1 ] [1] [1]
-
[ 1 ] [1] [1]
-
[ 6 , 5 , 4 , 3 , 2 , 1 ] [6,5,4,3,2,1] [6,5,4,3,2,1]
-
[ 2 , 1 ] [2,1] [2,1]
所有剩下的序列只包含不同的元素。
解法
对于每个序列,只需要找出从后往前第一个与之后的数字重复的数字的下标即可。不存在这个数字输出 0 0 0。
考虑使用STL中的set容器,从后往前遍历每个序列元素,若不在set中则加入set,若已经存在,下标就是答案。可设置一个虚拟元素 a 0 = a 1 a_0=a_1 a0=a1 ,遍历从 n n n 到 0 0 0 ,若 [ a 1 , a 2 , … , a n ] [a_1,a_2,\dots,a_n] [a1,a2,…,an] 中无重复数字, 0 0 0 就是答案。
核心代码:
int t,n,a[200001];
set<int>st;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
st.clear(); //使用前清空容器
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
a[0]=a[1]; //虚拟元素
for(int i=n;i>=0;i--) //遍历
if(st.count(a[i])) //判断当前元素是否与已进入容器的元素重复
{
cout<<i<<'\n'; //重复,下标即为答案
break;
}
else
st.insert(a[i]); //不重复,加入容器
}