双指针算法(超详细)

题目1-最长连续不重复子序列

给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。

输入格式
第一行包含整数 n。

第二行包含 n 个整数(均在 0∼105 范围内),表示整数序列。

输出格式
共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度。

数据范围
1≤n≤105
输入样例:
5
1 2 2 3 5
输出样例:
3

//算法思想:用一个长度为100000的数组b来记录每个数字出现的次数,若数据出现就加上1.
//利用双指针,i是先头兵,j在后面收尾,先头兵i每次都往前前进一部,j在后面找到与当前
//的i匹配的最佳的不重复的序列的长度。输出最长的那个。

#include
#include
#include
#include

using namespace std;

const int  N=100000;

int a[N],b[N];

int main(){

    int n;
    cin>>n;

    for(int i=0;i<n;i++) cin>>a[i];

    int res=0,j=0;
    for(int i=0;i<n;i++){
        b[a[i]]++;     //遍历过的a[i]中的元素在b[i]中的计数加1.
        while(b[a[i]]>1){  //如果其中的某个元素出现的次数大于1,就要移动j。
            b[a[j]]--;  //j移动之前要把用来计数的b数组减去一
            j++;        //j向后移动一位
        } 
        res=max(res,i-j+1);
    }

    cout<<res;
    return 0;
}

算法思想:用一个长度为100000的数组b来记录每个数字出现的次数,若数据出现就加上1.
利用双指针,i是先头兵,j在后面收尾,先头兵i每次都往前前进一部,j在后面找到与当前
的i匹配的最佳的不重复的序列的长度。输出最长的那个。

题目2 判断子序列

给定一个长度为 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。

数据范围
1≤n≤m≤105,
−109≤ai,bi≤109
输入样例:
3 5
1 3 5
1 2 3 4 5
输出样例:
Yes

//算法思想;设置两个指针分别指向两个数组的起始的位置,如果所指向的两个元素相同,则两个指针向前移动一位;
//如果两个元组不同,则只移动b、数组上面的指针。终止条件是如果a上面的指针指向的是最后一个元素的后面,那
//么就输出yes,否则输出no

#include
#include
#include
#include

using namespace std;

const int N=100010;

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 i=0;i<m;i++) cin>>b[i];

    int j=0; int i; //j是指向数组a的指针
    for(i=0;i<m;i++){ //i是指向数组b的指针
        if(a[j]==b[i]) j++;
        if(j==n) break;  //当满足条件时,跳出循环。
    }
    //cout<
    if(j==n) printf("Yes");
    else printf("No");

    return 0;
}

算法思想;设置两个指针分别指向两个数组的起始的位置,如果所指向的两个元素相同,则两个指针向前移动一位;如果两个元组不同,则只移动b、数组上面的指针。终止条件是如果a上面的指针指向的是最后一个元素的后面,那么就输出yes,否则输出no

题目3 数组元素的目标和

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

数组下标从 0 开始。

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

数据保证有唯一解。

输入格式
第一行包含三个整数 n,m,x,分别表示 A 的长度,B 的长度以及目标值 x。

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

第三行包含 m 个整数,表示数组 B。

输出格式
共一行,包含两个整数 i 和 j。

数据范围
数组长度不超过 105。
同一数组内元素各不相同。
1≤数组元素≤109
输入样例:
4 5 6
1 2 4 7
3 4 6 8 9
输出样例:
1 1

//算法思想:由于两个数组都是升序排列,所以可以利用双指针,其中一个指针指向数组A的最右端,另一个指针
//指向数组B的最左端,分别向左和向右移动。当当前指针指向的两个数的和大于目标值时,指向A的指针向左移
//动;当当前指针指向的两个数的和小于目标值时,指向B的指针向右移动;当相等时输出。
//此外,不用考虑有相同的值的情况,因为题目中交代了数据保证有唯一解。

#include
#include
#include
#include

using namespace std;

typedef long long ll;

const int N=100000;
ll  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];

    int j=0,i=n-1; 
    //i指向数组a的最右端,j指向数组b中的最左端。
    while(1){
        ll tmp;
        tmp=a[i]+b[j];
        if(tmp>x) i--;//如果当前两个数的和比x大,i左移
        if(tmp<x) j++;//如果当前两个数的和比x小,j右移
        if(tmp==x) break;
    }

    cout<<i<<" "<<j;

    return 0;
}

算法思想:由于两个数组都是升序排列,所以可以利用双指针,其中一个指针指向数组A的最右端,另一个指针指向数组B的最左端,分别向左和向右移动。当当前指针指向的两个数的和大于目标值时,指向A的指针向左移动;当当前指针指向的两个数的和小于目标值时,指向B的指针向右移动;当相等时输出。此外,不用考虑有相同的值的情况,因为题目中交代了数据保证有唯一解。

你可能感兴趣的:(算法,c++,数据结构)