双指针算法

算法-双指针算法

一.基本模板
#include<bits/stdc++.h>
using namespace std;

int main()
{
	for(int i = 0, j = 0 ; i < n ; i ++)
	{
		while(j < m && check()) j++;
		// 具体题目的逻辑应用
	}
}
案例一

题目,有一个字符串“abc dhg jaj lll ahin”,要求输出单词,换句话说就是去掉空格。
输入:“abc dhg jaj lll ahin”字符串
输出:
abc
dhg
jaj
lll
ahin

代码:

#include<iostream>
#include<string.h>
#include<algorithm>
#include<cstring>

using namespace std;

int main()
{
    char str[1000];
    cin.getline(str,100);
    //**cin会过滤空格**
    int n = strlen(str);
    for(int i = 0  ; i < n ; i++)
    {
        int j = i ;
        while(j < n && str[i] != ' ') j++;
        
        //判断条件
        for(int k = i ; k < j ; k++)
        {
            cout << str[k] ;
        }
        cout << endl;
        i = j;
    }
    return 0;
}


总体解释:就是i为从左到右所选单词的起点,而j是一个一直往右走的单词的后端点,如果没有空格就一直往后走,有空格说明可以输出单词了,通过k变量来输出单词,同时改变i的起点位置,下一层循环开始后,j也重新从新的i起点开始继续查找。

案例二

题目:给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。
输入:第一行包含整数 n,第二行包含 n 个整数(均在 0∼100000 范围内),表示整数序列。
输出:共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度。

#include<iostream>

using namespace std;

const int N = 1e5+10;

int a[N];
int s[N];

int main()
{
    int n,res = 0;
    cin >> n;
    for(int i = 0 ; i <n ; i++)
    {
        cin >> a[i];
    }
    for(int i = 0 , j = 0 ; 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;
}

思路:还是通过双指针,i代表的是每次往后移动的右端点,j是永远小于i的,通过是s[k]数组来记录数值为k的数是否与之前加入的元素是否重复,这里的k就是a[i],每次i移动一次,就把新加入的元素导入s[a[i]]++,同时判断新加入的元素是否影响原来的数组,如果不影响就更新最大值,如果影响就把j++,同时把左端的元素踢出去就是s[a[j]]–,直到没有重复为止,最后输出最大值。

案例三

题目:给定两个升序排序的有序数组 A 和 B,以及一个目标值 x。

数组下标从 0 开始。

请你求出满足 A[i]+B[j]=x 的数对 (i,j)。

数据保证有唯一解。
输入:第一行包含三个整数 n,m,x,分别表示 A 的长度,B 的长度以及目标值 x。

第二行包含 n 个整数,表示数组 A。

第三行包含 m 个整数,表示数组 B。
输出:
共一行,包含两个整数 i 和 j。
代码:

#include<iostream>
#include<algorithm>

using namespace std;
const int N = 1e5+10;

int a[N],b[N];

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

案例四:

题目:给定一个长度为 n 的整数序列 a1,a2,…,an 以及一个长度为 m 的整数序列 b1,b2,…,bm。

请你判断 a 序列是否为 b 序列的子序列。

子序列指序列的一部分项按原有次序排列而得的序列,例如序列 {a1,a3,a5} 是序列 {a1,a2,a3,a4,a5} 的一个子序列。
输入:
第一行包含两个整数 n,m。

第二行包含 n 个整数,表示 a1,a2,…,an。

第三行包含 m 个整数,表示 b1,b2,…,bm。
输出:如果 a 序列是 b 序列的子序列,输出一行 Yes。

否则,输出 No。
代码:

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e5+10;

int a[N],b[N];

int main()
{
    int n,m;
    cin >> n >> m;
    for(int i = 0 ; i < n ; i++)
    {
        cin >> a[i];
    }
    for(int j = 0 ; j < m ; j++)
    {
        cin >> b[j];
    }
    bool t = true;
    for(int i = 0,j = 0 ; i < n ; i++)
    {
        while(j < m && a[i] != b[j]) j++;
        if(a[i]!= b[j])
        {
           t = false;
           break;
        }
        j++;
    }
    if(t) puts("Yes");
    else{
        puts("No");
    }
    return 0;
}

优雅的代码:

#include <iostream>
#include <cstring>

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) puts("Yes");
    else puts("No");

    return 0;
}


思路:也是从左到右两个坐标一起往右刷,直到找到一个相等的元素,不然就判定不符合要求,之后就是不断往后移动了,和前面的思路一样。

案例五

题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

假设字符串中只包含从 a 到 z 的字符。
样例:
输入:“abcabc”

输出:3
代码:

class Solution {
public:
    int longestSubstringWithoutDuplication(string s) {
        unordered_map<char,int> hash;
        int n = s.size();
        int res = 0;
        for(int i = 0, j = 0 ; i < n ; i++)
        {
            hash[s[i]]++;
            while(hash[s[i]] > 1) hash[s[j++]]--;
            res = max(res,i - j + 1);
        }
        return res;
    }
};

思路:和案例二差不多,只是把数字换成了字符串。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值