最长连续不重复子序列

这是一道基于双指针算法的题目,但是想解这道题需要一点额外的思路,第一遍我没想出来,故在此对这道题的思路进行记录。

题目描述与输入输出

在这里插入图片描述

思路

这道题目的要求是寻找不包含重复的数的最长子序列,从题目来看可以使用双指针算法来进行求解,使用iii指针向后遍历,使用jjj指针记录合法的区间起点。

问题的难题在于如何对子序列中重复的数进行判断,即判断当前子序列是否满足题目条件。

正确的解决办法是使用另一个数组sss来记录子序列中数字出现的次数,它的角色有点像map,但由于题目描述中提到数字的大小不会大于10510^5105,因此直接使用另一个数组来存储该信息即可。

具体来说,以111作为数组的下标起点,初始化两个指针,使i=1, j=1,在每一次迭代的过程中都使i++,并使得s[a[i]] ++,这里的aaa数组是存储完整序列的数组,s[a[i]] ++的含义是使a[i]这个数在子序列的出现次数加一。

之后使用while循环来对jjj指针进行移动,如果s[a[j]] > 1,则说明a[j]这个数在子序列中出现了超过两次,需要将jjj指针右移,因为包含当前位置的子序列已经不满足“不重复”这条性质,持续地对s[a[j]]进行判断直到满足子序列的条件,停止jjj指针的移动。

此时,使用resresres来对答案进行记录,使得res = max(res, i-j+1)。

最后输出resresres就是最终答案。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 1e5 + 5;
int a[maxn] = {0};
int s[maxn] = {0};
int n;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    for(int i=1; i<=n; i++) {
        cin >> a[i];
    }
    int res = 0;
    for(int i=1, j=1; i<=n; i++) {
        s[a[i]] ++;
        while(s[a[i]] > 1) {
            s[a[j]] --;
            j ++;
        }
        res = max(res, i - j + 1);
    }
    cout << res;
    return 0;
}

更多推荐