分析:
对于每一个i找最靠左的j,使得从j–>i不包含重复数字,为了保证时间复杂度不是$O(N^2)$,而是$O(N)$,找单调性使用双指针算法优化。
证明单调性(略)
j不用往回退,只往右走,j不走回头路是关键
两个指针只往右走不回退,所以是$O(2N)$,期间可以使用数组或哈希表维护[j, i]中每个数字或字符出现的次数,i后移一位,则将下一个字符加入哈希表,看下此时集合中是否有重复元素,又由于只加了第i+1(下标)位元素,所以有重复元素必然是a[i+1]。只用判断a[i+1]的个数是否多余一个就行,如果多余一个,则把j往后移动,直到移动到某个a[i+1]为止并做s[a[j]]–(减掉新加元素个数)(就是把j移动到i位置上使得[i,j]内只有一个a[i])
核心思想是双指针算法,i指针是快指针,j是慢指针,每当i指针右移一位的时候,
其对应的元素的个数就需要,可以看出此处需要一个计数的数组
或者unordered_map<int, int>
,
如果是字符串或者字符等元素的话,建议用后者。unordered_map<int, int>
接下来介绍check函数,check函数的实现功能就是,当s[a[i]]>1的话,我们就持续j,
并且将s[a[j]]–,这一步绝对不能省。
第三步就是最后的操作了res = max(res, i - j + 1);
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N], s[N];
int main () {
int n;
cin >> n;
for (int i = 0; i < n; i ++) cin >> a[i];
int res = 0;
for (int i = 0, j = 0; i < n; i ++) {
s[a[i]] ++;
while (s[a[i]] > 1) s[a[j ++]] --;
res = max(res, i - j + 1);
}
cout << res << endl;
return 0;
}