题面链接
题意:对于一个序列L,如果其元素个数大于1,其众数是c,那么我们称L由c主导,给出一个长为n的序列,要你找出它最短的子序列,使得其由某个数主导,注意{1,1,2,2}这样的序列不能满足条件,也就是众数不能有多个。
思路:如果有两个连续的相同数字,那么答案就是2,那么我们在原序列找出两个相同数字的距离,所有这样的距离的最小值就是所求答案,因为我们对于两个相同数字求出一个距离,如果它们之间还有两个相同数字,必然可以得到一个更加短的距离,这就是我们的贪心策略。
具体方法是对数组扫一遍,记录当前数字最后出现的位置,如果他不是第一次出现,那么求一下它和上一次出现位置的距离,更新ans=min(ans,当前计算的距离)。
误区:当时卡点是因为我以为最后序列的众数要和原序列一样,一直在想找众数的方法和原众数生成的最小序列。
AC代码:
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
#define ll long long
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
ll min(ll x, ll y) {return x < y ? x : y;}
const int maxn = 2e5 + 5;
#define INF 0x3f3f3f3f
const int mod = 1e9 + 7;
ll n,arr[maxn],brr[maxn],mk[maxn];
int main() {
int t;
cin>>t;
while(t--){
n=read();
for(ll i=0;i<n;i++) arr[i]=read();
if(n==1){cout<<-1<<endl;continue;}
memset(mk,-INF, sizeof mk);
memset(brr,INF,sizeof brr);
ll ans=INF;
for(ll i=0;i<n;i++){
if(mk[arr[i]]!=-INF) brr[arr[i]]=min(brr[arr[i]],i-mk[arr[i]]+1);//记录两个相同arr[i]间隔的最短距离
mk[arr[i]]=i;//记录最后一个arr[i]出现的位置
ans=min(ans,brr[arr[i]]);//更新记录所有数的最短距离
}
//for(ll i=1;i<=n;i++) cout<<mk[i]<<' ';cout<<endl;
if(ans<INF) cout<<ans<<endl;
else cout<<-1<<endl;
}
return 0;
}