双指针算法

简介: 复习acwing算法基础课的内容,本篇为讲解基础算法:双指针算法,关于时间复杂度:目前博主不太会计算,先鸽了,日后一定补上

文章目录

前言

一、双指针算法概述

二、双指针算法模板及例题

1.模板

2.AcWing799. 最长连续不重复子序列

AC代码

代码分析

3.AcWing 800. 数组元素的目标和

AC代码

代码分析

4.AcWing2816. 判断子序列

AC代码

代码分析

三、时间复杂度


前言

复习acwing算法基础课的内容,本篇为讲解基础算法:双指针算法,关于时间复杂度:目前博主不太会计算,先鸽了,日后一定补上


一、双指针算法概述

这里的指针不是我们知道的 * ,这里的双指针是例如用 i 和 j 去维护一段区间,大致形式如:

for (int i = 0; i < n; i ++ )
  for (int j = 0; j < i; j ++ )
  {
    ......
  }

二、双指针算法模板及例题

1.模板

本算法模板来自:AcWing算法基础课

for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < i && check(i, j)) j ++ ;        //check函数指 i,j之间除了j < i的其他关系
    // 具体问题的逻辑
}

2.AcWing799. 最长连续不重复子序列

本题链接:AcWing799. 最长连续不重复子序列

本博客给出题目截图:

image.png

AC代码

#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N], s[N];
int main()
{
    int n, ans = 0;
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    for (int i = 0, j = 0; i < n; i ++ )
    {
        s[a[i]] ++;
        while (s[a[i]] > 1)
        {
            s[a[j]] --;
            j ++;
        }
        ans = max (ans, i - j + 1);
    }
    printf("%d", ans);
    return 0;
}

代码分析

本题利用双指针算法,因为题目保证 a[i] 中的每一个数都是属于[0, 1e5] 的,所以可以用s[a[i]]去存储 a[i] 出现了多少次,每出现一次就把 s[a[i]] ++; 所以如果当 s[a[i]] > 1 的时候就证明出现了重复的数字,本题双指针算法维护的是从 j 开始到 i 结束的这么一段子区间,只要不满足 s[a[i]] > 1 这一条件,j 就不动,i 往后移动一个单位,直到出现了 s[a[i]] > 1,证明维护的这一子区间内出现了重复的元素,我们就把 j 往后移动一位,每次 i 更新的时候都计算一下当前子区间的长度更新 ans.

    for (int i = 0, j = 0; i < n; i ++ )         //因为j始终是小于i的,所以当i走到终点即可
    {
        s[a[i]] ++;
        while (s[a[i]] > 1)
        {
            s[a[j]] --;
            j ++;
        }
        ans = max (ans, i - j + 1);
    }

3.AcWing 800. 数组元素的目标和

本题链接:AcWing 800. 数组元素的目标和

本博客给出本题截图:

image.png

AC代码

#include <cstdio>
using namespace std;
const int N = 100010;
int a[N], b[N];
int main()
{
    int n, m, x;
    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 (a[i] + b[j] > x) j --;           //这里的while中不需要加 j >= 0,因为保证一定有解
        if (a[i] + b[j] == x)
        {
            printf("%d %d", i, j);
            break;                              //找到目标值就退出,因为保证有唯一解
        }
    }
    return 0;
}

代码分析

如下代码会TLE:这个代码就是纯暴力代码了,时间复杂度是O(n²),那么对比我们这个代码和AC的代码,AC的代码优化在哪里了呢?

//错误代码:
   for (int i = 0; i < n; i ++ )
       for (int j = 0; j < m; j ++ )
           if (a[i] + b[j] == x)
           {
               printf("%d %d", i, j);
               exit(0);                          //exit(0); 需要添加头文件 #incldue <cstdlib>
           }

这个错误代码 i 和 j 都是从 0 开始的,而AC的代码中 i 是从0开始的,j 是从 m - 1开始的,即数组a是正序遍历,数组b是逆序遍历,这么遍历的优点在于,因为数组a和数组b都是满足严格上升的,如果满足 i + j > x 的条件,那么 i 是不需要再往后移动的,只需要 j 往前移动就好了,正所谓双向的奔赴要好于单方向的追求,i 和 j 同时向一个值靠近要优于 i 和 j 一直试错的靠近.


4.AcWing2816. 判断子序列

本题链接:AcWing2816. 判断子序列

本博客给出本题截图:

image.png

AC代码

#include <cstdio>
using namespace std;
const int N = 100010;
int a[N], b[N];
int main()
{
    int n, m;
    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;
    for (;i < n && j < m; j ++ )
        if (a[i] == b[j]) i ++;
    if (i == n) puts("Yes");
    else puts("No");
    return 0;
}

代码分析

判断数组a是否是数组b的子序列:

image.png

如图,我们依次对比a数组和b数组的每一个元素,如果不匹配的话,就让数组b向后移动一个单位,如果匹配的话就让数组b和数组a都往后移动一个单位,如果最后a数组的每一个元素在数组b中都有对应元素,则输出Yes,否则输出No

    int i = 0, j = 0;
    for (;i < n && j < m; j ++ )
        if (a[i] == b[j]) i ++;

三、时间复杂度

关于双指针算法的时间复杂度以及证明,后续会给出详细的说明以及证明过程,目前先鸽了。

目录
相关文章
|
12天前
|
算法 前端开发 JavaScript
< 每日算法:一文带你认识 “ 双指针算法 ” >
`双指针`并非指的是一种具体的公式或者范式。而是一种运算思路,用于节省逻辑运算时间的`逻辑思路`!双指针算法通常用于`优化时间复杂度`!
< 每日算法:一文带你认识 “ 双指针算法 ” >
|
16天前
|
算法
|
22天前
|
算法
优选算法|【双指针】|202.快乐数
优选算法|【双指针】|202.快乐数
|
23天前
|
算法
【优选算法专栏】专题一:双指针--------1.移动0
【优选算法专栏】专题一:双指针--------1.移动0
19 0
|
2月前
|
算法 关系型数据库 MySQL
大厂算法指南:优选算法 ——双指针篇(下)
大厂算法指南:优选算法 ——双指针篇(下)
28 0
|
2月前
|
算法 容器
算法思想总结:双指针算法
算法思想总结:双指针算法
|
2月前
|
存储 算法 容器
【优选算法】—— 双指针问题
【优选算法】—— 双指针问题
【优选算法】—— 双指针问题
|
2月前
|
算法
我对双指针算法认知
我对双指针算法认知
|
3月前
|
算法 测试技术 C++
【双指针】【C++算法】1537. 最大得分
【双指针】【C++算法】1537. 最大得分
|
10天前
|
C语言
C语言:数组和指针笔试题解析(包括一些容易混淆的指针题目)
C语言:数组和指针笔试题解析(包括一些容易混淆的指针题目)