最长连续不重复子序列----双指针模版题

本文讲述了如何通过双指针优化算法解决最长连续不重复子序列问题,避免了暴力两层循环带来的高时间复杂度。通过计数数组实现空间换时间,将时间复杂度从O(n^2)降低到O(n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 题目描述如下:

双指针的核心思想:当要处理两层循环时,找到i与j的某种条件,使答案不用经过两次循环(O(n*2))而是经过i的一轮循环,通过i和j的关系确定j,将时间优化到O(n)

具体举例就如上题所示,寻找最长连续不重复子序列,我们当然可以通过暴力两层循环模拟题目描述的到答案,但数据范围1e5,当两层循环后1e10的计算量是大于我们计算机1e8每秒的运算次数,会使有些数据超时,此时我们考虑优化算法

暴力代码如下: 

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],cnt[N];//cnt数组用于记录每个元素出现的次数
int n,res;
//检查从i到j元素a[j]是否出现过,
bool check(int i,int j){
    for(int k=i;k<j;k++){
        if(a[k]==a[j]) return false;
    }
    return true;
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    for(int i=0;i<n;i++){
        for(int j=i;j<n;j++){
            while(check(i,j)==false){  //只要i到j中还有重复元素,让i右移动
                i++;
            }
            res=max(res,j-i+1);
        }
    }
    cout<<res;
}

优化算法的方法常常有二分,前缀和,双指针等小技巧,这里要求区间而非找数(临界),故与二分无关,求区间长度而非区间内与值相关的问题,前缀和大概率也用不上,再寻找区间(有两个变量)的问题上,我们可以考虑双指针

本题的思想有点类似哈希表,用空间换取时间,我们可以发现在暴力中,在考虑新加入的a[j]在区间[i,j]是否出现过时,没必要一遍遍跑一遍从i到j,我们可以通过一个计数的数组(学过桶排序的可能更好理解),只要数组中某一个数出现的次数(被计数的次数)大于1时,这时该区间就不满足要求,我们让左端点不断向右移动,寻找下一个(无重复元素的)区间,我们通过这个计数的数组,实现了i和j关系的连接

ac代码如下: 

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],cnt[N];//cnt数组用于记录每个元素出现的次数
int n;
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    int mx=0;
    for(int i=0,j=0;j<n;j++){
        cnt[a[j]]++;
        while(cnt[a[j]]>1){
            cnt[a[i]]--;//i向右移,记录a[i]数组中a[i]的个数减一
            i++;//i 右移
        }
        mx=max(mx,j-i+1);
    }
    cout<<mx;
}

题目来源: 799. 最长连续不重复子序列 - AcWing题库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值