双指针算法

Posted on 2022-02-19 11:05  ZheyuHarry  阅读(84)  评论(0编辑  收藏  举报

                  我们将要引入一个双指针算法,我们考虑为什么要引入双指针算法呢,以及双指针算法究竟能为我们解决什么样的问题?

       

              通常,我们会处理到有些问题需要遍历某个序列,但根据题意我们并不需要重复判断某些过程,所以我们会利用双指针算法来取代朴素算法。将时间复杂度为O(n^2)的算法优化到O(n),就是可以不需要重复遍历某些元素。

              举个栗子:

              我们已知一个序列arr,我们要求出最长无重复数字的连续子串,我们用i指向右边的终点,j指向左边的起点,我们的问题是当i指向当前数字时,j最远能走到哪个位置,而当i指针往右走过去时,j指针只能向右走,不可能向左走,不然的话就向两端扩大了序列,一定会产生重复子串,这就是O(n)的算法,比起双重遍历去最值的好了太多!

              如图:

                                    

 

 

                            这样我们就可以知道,双指针是一个怎样的优秀算法,但是呢,我们总要先抽取出一些双指针算法的核心:

                      我们在遍历i的时候,只要j在范围区间之内,以及j满足某些check的条件的话,我们就可以让j++或者j--;

 

                      然后我们要大概分个几类双指针的具体算法:

                      ·快慢指针:

                      ·对撞指针:

                                某个序列我们分别让i指针从头开始,某个序列从尾开始,然后满足某种条件时停下或者完成某些操作;

                                举两个栗子:

                              ·  快速排序的时候我们会定义一个x,令i指针左边都比x小,j指针右边都比x大,当arr[i]>=x 把i指针停下,当arr[j]<=x 把j指针停下,然后互换两个指针所指向的值,然后递归处理子问题,边界条件是i<=j。

                              ·编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

                               这个也是对撞指针,和上面差不多,只是停下指针的条件变成了遇到元音字母;然后swap两者。

                       ·滑动窗口:

                        有左右端点和长度,根据题目调整左右端点的位置进行滑动,也是一种特殊的双指针

                         栗子:上面的最长无重复字符子串;

                         有些时候不仅仅是一维数组的滑动窗口,还是二维窗口的滑动窗口

                         比如:2816. 判断子序列 - AcWing题库

 

                         板子:

 

 

#include<bits/stdc++.h>
#define maxn 100010

 

using namespace std;
int n;
int a[maxn],s[maxn];

 

int main()
{
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int res = 0;
for(int i=1,j=1;i<=n;i++){
s[a[i]]++;
while(s[a[i]]>1){
s[a[j]]--;
j++;
}
res = max(res,i-j+1);
}
cout<<res<<endl;
return 0;
}

 

 

双指针算法也比较特殊:

 我们之后会引入一些比较有特殊性质的例题:

·2816. 判断子序列 - AcWing题库

·AcWING 799. 最长连续不重复子序列 - AcWing

·800. 数组元素的目标和 - AcWing题库