1. 概念
双指针通过两个指针以不同速度和条件来遍历某个区间,在遍历期间能够找到符合特定条件的元素或者子区间。
2. 思路
一般的双指针算法 都存在一个暴力算法 ,即O(n^2)时间复杂度 的算法,我们可以观察暴力算法的两次循环是否存在某种单调关系,如果存在可以通过双指针进行优化成为O(n)的时间复杂度。
我们首先定义右指针r
和左指针l
,每当右指针r
向后移动的时候,都去判断左指针l
所能达到的最左端。同时需要注意的是,r指针
和l指针
都只会向后移动,不可能出现r指针
后移,l指针
左移的情况。
假设2-4范围是当前符合条件的区间,如果1-5也是符合条件的区间,那么1-4也是符合条件的区间,那么假设失败。
常见的滑动窗口问题 ,我们可以通过定义两个指针,分别表示窗口的左端和右端,通过移动左、右端下标来对窗口进行移动,需要注意的是,左端下标一定小于等于右端下标。
3. 代码模板
c++
for(i = 0, j = 0; i < n; i++)
{
while(j < i && check(i, j)) j++;
// 每道题的具体逻辑
}
4. 注意点
常见问题分类:
- 对于一个序列,用两个指针维护一段区间
- 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
5. 例题
5.1. 最长连续不重复子序列 - AcWing题库
c++
#include <iostream>
using namespace std;
const int N = 100010;
int n;
int a[N], s[N];
int main()
{
cin >> n;
for(int i = 0; i < n; i++) cin >> a[i];
int res = 0;
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 << endl;
return 0;
}