问题
给定一个长度为n的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。
输入格式
第一行包含整数n。
第二行包含n个整数(均在
0
0
0~
1
0
5
10^5
105范围内),表示整数序列。
输出格式
共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度
输出范围
1 < = n < = 1 0 5 1<=n<=10^5 1<=n<=105
输出样例
3
题目解析: 双指针法
- 遍历数组a中的每一个元素a[i],对于每一个i,找到j使得双指针[j, i]维护的是以a[i]结尾的最长连续不重复子序列,长度为i - j + 1,将这一长度与r的较大者更新给r。
- 对于每一个i,如何确定j的位置:由于[j, i - 1]是前一步得到的最长连续不重复子序列,所以如果[j, i]中有重复元素,一定是a[i],因此右移j直到a[i]不是重复元素位置(由于[j, i - 1]已经是前一步的最优解,此时j只可能右移以剔除重复元素a[i],不可能左移添加元素,因此,j具有“单调性”,本题可用双指针降低复杂度)。
- 用数组s记录子序列a[j]~a[i]中各元素出现的次数,遍历过程中对于每一个i有四步操作:
- cin 元素 a[i]
- 将a[i]出现的次数s[a[i]]加1
- 若a[i]重复则右移j(s[a[j]]要减1)
- 确定j及更新当前长度i - j + 1给r
代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N];
int s[N]; // 此为频率标记数组
int main()
{
int n;
cin >> n;
int j = 0; // 左指针j
int r = 1; // 中间过程的长度
int max = 1; // 计算最大的子序列的长度
for(int i=0; i<n; i++)
{
cin >> a[i]; //首先cin元素a[i]
s[a[i]]++; // 将a[i]出现的次数s[a[i]]加1
if(s[a[i]] == 2)
{
// 若a[i]重复,则右移j
while(j < n)
{
s[a[j]]--; //在右移j之前要将右移之前时候的a[j]的数量减1
j++; // 右移j
if(s[a[i]] == 1)
{
// 若重复的a[i]不再变得重复,此时将会是此次i指针下的最长子序列长度
r = i - j + 1; // 这里更新下中间过程的长度r
if(max < r)
{
max = r;
}
break;
}
}
}
else if(s[a[i]] == 1)
{
// 若a[i]不重复,则也需要更新下长度r
r = i - j + 1;
if(max < r)
{
max = r;
}
}
}
cout << max;
return 0;
}