双指针算法的实现(三题详解)

         这是C++算法基础-基础算法专栏的第十五篇文章,专栏详情请见此处


ps:转眼间暑假已过半,我在这段时间也积累了很多文章,所以到开学(9月1日)为止,每个周我将会在周三和周六发文章(o゚▽゚)o  

引入

        双指针是一种解决问题的一种方法,我们可以在题目中挖掘一些性质,并使用双指针算法优化时间复杂度。

        下面我们就来讲双指针算法的实现。

定义

        双指针是一种简单而又灵活的技巧和思想,单独使用可以轻松解决一些特定问题,和其他算法结合也能发挥多样的用处。

        双指针顾名思义,就是同时使用两个指针,在序列、链表结构上指向的是位置,在树、图结构中指向的是节点,通过或同向移动,或相向移动来维护、统计信息。

过程

        双指针算法,从名字上就能看出,我们是用两个指针对序列进行操作的,具体有两种分类:

  1. 对于一个序列,用两个指针维护一段区间
  2. 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

        而双指针算法还可以通过问题类型分类,较简单与常见的有三种,接下来我们就用三道题目来详细讲解:

        1. 维护区间信息

        如果不和其他数据结构结合使用,双指针维护区间信息的最简单模式就是维护具有一定单调性,新增和删去一个元素都很方便处理的信息。

        例题:AcWing-799. 最长连续不重复子序列

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

        具体思路:在一个区间中维护两个指针i,ji遍历每一个位置j记录当前序列起始位置。首先,两个指针从头开始;然后i进行遍历,并开一个额外的数组s记录区间\left [ i,j \right ]每个数字出现的次数(就是开一个桶),每次i移动时,桶内的数加一;然后判断,如果此时当前桶数字大于1,就说明目前r指针所指的位置重复了;这时,记录序列长度,即i-j+1,打擂台求出最大值,然后j数组不断向前移动,将s中存储的数字出现的次数减去1,直到遇到i为止;最后,存储最大值的变量记录的就是最长连续不重复子序列的长度。

        2. 维护有序序列

        很多时候在序列上使用双指针之所以能够正确地达到目的,是因为序列的某些性质,最常见的就是利用序列的有序性。

         例题:AcWing-800. 数组元素的目标和

        题目大意:给定两个升序排序的有序数组AB,以及一个目标值x,求出满足A\left [ i \right ]+B\left [ j \right ]=x的数对\left ( i,j \right )

        具体思路:由于两数之和固定,那么两数之中的小数越大,大数越小,那我们不妨从两个数组的两边接近它们。首先,两个指针i,j分别位于A0号位和Bn-1号位;然后i先开始往后移动,此时A\left [ i \right ]+B\left [ j \right ]会逐渐变大,直到A\left [ i \right ]+B\left [ j \right ]>x,此时调整j的位置(往前移动),直到A\left [ i \right ]+B\left [ j \right ]不大于x,当调整完后,进行判断,如果A\left [ i \right ]+B\left [ j \right ]= x,那么就找到了答案,结束循环;如果A\left [ i \right ]+B\left [ j \right ]<x,那么继续调整i,j的位置,最后两者将会逼近到答案。

        3. 子序列匹配

          例题:AcWing-2816. 判断子序列

        题目大意:给定一个长度为n的整数序列a以及一个长度为m的整数序列b,请你判断序列a序列是否为b序列的子序列。

        具体思路:维护两个指针i,jia数组开始位置遍历,jb数组开始位置遍历;j先开始往后移动,直到a\left [ i \right ]=b\left [ j \right ],将i,j同时加一,再继续遍历;最后,当b数组遍历到最后一位时,说明已经比对完毕,只用看看a数组有没有遍历完,如果遍历完毕,则说明a序列是为b序列的子序列,反之不是。

性质

        时间复杂度

        双指针算法的时间复杂度一般是O\left ( n \right )的。

Q:双指针算法有两个指针,代码上也是两重循环,看似是O\left ( n^{2} \right )的时间复杂度,为什么时间复杂度是O\left ( n \right )的呢?

A:最最核心的就是,两个指针都是同时遍历的他们只会从头走到尾,因此时间复杂度是O\left ( 2n \right ),在O\left ( n \right )量级。

代码

        下面给出双指针算法的实现代码:

for(int i=0,j=0;i<n;i++){
    while(j<i&&check(i,j)) j++;
    
}
        代码解释

        check()函数的作用是检查i,j是否满足某种性质;while循环下一行是写具体问题的逻辑的。


上一篇-二维差分的实现    C++算法基础专栏文章    下一篇-位运算的实现


每周六更新一篇文章,内容一般是自己总结的经验或是在其他网站上整理的优质内容

点个赞,关注一下呗~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值