算法基础--双指针算法

双指针算法

核心思想

  • 暴力枚举解题
  • 观察是否有单调性,有则可以使用双指针降低时间复杂度

最长连续不重复子序列

核心思想 :

  1. 遍历数组a中的每一个元素a[i],计算每一个以a[j]开始a[i]结尾的连续子序列的长度,并将长度i - j + 1 与较大的 res 比较并更新(res = max(res, i - j + 1));
  2. 对于每一个i,如何确定j的位置:由于[j, i - 1]是前一步得到的最长连续不重复子序列,所以如果[j, i]中有重复元素,一定是a[i],因此右移j直到a[i]不重复为止([j, i - 1]已经是前一步的最优解,由于i 和 j 都具有单调性,j不可能左移,所以出现重复的数字只能是a[i]);
  3. 用数组s记录子序列a[ j ] ~~~ a[ i ] 中各元素出现次数。若s[ a[ i ] ] > 1了则代表出现了重复的数字 a[ i ] ,通过 j ++ 来移动子序列的左边界,直到将出现的第一个数 a[ i ] 排除出去。{ while (s[a[i]] > 1) }时执行 { s[ a[i] ] - - } { j ++ } //先将丢弃的数字出现的次数减去,再把 j 右移;
#include<iostream>

using namespace std;

const int N = 1e5 + 10;
int n;
int a[N],s[N];

int main()
{
    scanf("%d",&n);
    for(int i = 0; i < n; i ++) scanf("%d", &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;
}

数组元素的目标和

题目 :

给定两个升序排序的有序数组 A 和 B,以及一个目标值 x。
数组下标从 0 开始。
请你求出满足 A[i]+B[j]=x 的数对 (i,j)。
数据保证有唯一解。

解题 :

  • 列出暴力枚举公式(两个for循环)。
  • 两数组单调递增,使用双指针,降低时间复杂度。
#include<iostream>
using namespace std;

const int N = 1e5 + 10;
int n,m,x;
int a[N], b[N];

int main()
{
    scanf("%d%d%d",&n, &m, &x);
    for(int i = 0; i < n; i ++) scanf("%d", &a[i]);
    for(int i = 0; i < m; i ++) scanf("%d", &b[i]);
    
    for(int i = 0, j = m - 1; i < n; i ++)
    {
        while(j >= 0 && a[i] + b[j] > x) j --;
        if(j >= 0 && a[i] + b[j] == x)
        {
            cout << i << ' ' << j << endl;
            break;
        }
    }
    return 0;
}

判断子序列

题目:

给定一个长度为 n 的整数序列 a1,a2,…,an 以及一个长度为 m 的整数序列 b1,b2,…,bm。
请你判断 a 序列是否为 b 序列的子序列。
子序列指序列的一部分项按原有次序排列而得的序列,例如序列 {a1,a3,a5} 是序列 {a1,a2,a3,a4,a5} 的一个子序列。

#include<iostream>

using namespace std;

const int N = 100010;
int n, m;
int a[N],b[N];

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i ++) scanf("%d", &a[i]);
    for(int i = 0; i < m; i ++) scanf("%d", &b[i]);
    
    int i = 0, j = 0;
    while(i < n && j < m)
    {
        if(a[i] == b[j]) i ++;
        j ++;
    }
    
    if(i == n) printf("Yes");
    else printf("No");
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值