題目點此跳轉
思路
題目意思是輸入一個長度爲n(n≤106)的序列A,找到一個儘量長的連續子序列
首先定義L和R表示要找的結果的左右端點,一開始L = R = 0;
然後我們不斷地增加R,直到不能增加了爲止,不能增加是因爲再增加的話就有相同的元素了;
這個時候我們維護一下最大值,然後開始增加L,直到將那個使R不能再增加的元素去掉爲止;
接着我們就又能繼續增加R了,直到R到序列尾。
我們會有一個直觀的感覺, 這裏的[L, R] 就像一個窗口一樣, 一開始在最左邊,然後不斷地向右邊滑動, 而且不會滑回來,因爲R是不斷增加的,L也是不斷增加的。這大概就是滑動數組了吧。
還有一點,我們可以用map來預處理出每一位元素上一次出現的位置, 這樣L往後跳的時候就不用一位一位地找了。
代碼
#include <algorithm>
#include <iostream>
#include <sstream>
#include <utility>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <cstring>
#include <cstdio>
#include <cmath>
#define met(a,b) memset(a, b, sizeof(a));
#define IN freopen("in.txt", "r", stdin);
#define OT freopen("out.txt", "w", stdout);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 1e6 + 100;
const int INF = 0x7fffffff;
const int dir[5][2] = {0,0,-1,0,1,0,0,-1,0,1};
const LL MOD = 1e9 + 7;
int n, a[maxn];
int pre[maxn];
map<int, int> m;
int main() {
#ifdef _LOCAL
IN; //OT;
#endif // _LOCAL
int t; cin >> t;
while(t--) {
scanf("%d", &n); m.clear();
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for(int i = 1; i <= n; ++i) {
if(!m.count(a[i])) pre[i] = -1;
else pre[i] = m[a[i]];
m[a[i]] = i;
}
int L = 1, R = 1, ans = 0;
while(R <= n) {
while(R+1 <= n && pre[R+1] < L) ++R;
ans = max(ans, R-L+1); ++R;
if(R > n) break;
L = pre[R]+1;
}
printf("%d\n", ans);
}
return 0;
}