常见分类
一、两个指针指向两个序列
对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
例如:归并排序
二、两个指针指向一个序列
对于一个序列,用两个指针维护一段区间
例如:快速排序
通用模板
for(i = 0,j = 0; i < n; i ++ )
{
while(j < i && check(i,j) j ++ ; //j在合法的范围并且满足某种性质
//每道题目的具体逻辑
}
核心思想
for(int i = 0; i < n; i ++ )
for(int j = 0; j < n; j ++ )
O(n^2)
将上面的朴素算法优化到O(n)
举个“栗子”^-^
双指针算法的一个简单应用,方便理解一下模板的使用
读入连续的字符串,以此输出字符串中的每个单词
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char str[1000];
//gets(str);
fgets(str, N, stdin);
int n = strlen(str);
for(int i = 0; i < n; i ++ )
{
int j = i;
while(j < n && str[j] != ' ') j ++ ;
//这道题的具体逻辑
for(int k = i; k < j; k ++ )
cout << str[k];
cout << endl;
i = j;
}
return 0;
}
//输入 abc def gh
//输出 abc
// def
// gh
注:gets()在c++14中已被删除
fgets()用法可参考:fgets函数及其用法,C语言fgets函数详解-CSDN博客
典例1——最长连续不重复子序列
朴素做法:O(n^2)
for(int i = 0; i < n; i ++ )
for(int j = 0; j <= i; j ++ )
if(check(j,j))
{
res = max(res,i - j + 1);
}
双指针算法:O(n)
for(int i = 0; i < n; i ++ )
{
while(j <= i && check(j,i))
res = max(res,i - j + 1);
}
#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]] ++ ; //记录数组a中元素出现次数
while(s[a[i]] > 1) //有重复元素出现
{
s[a[j]] -- ; //将j指针后移找到新的无重复元素的区间
j ++ ;
}
res = max(res,i - j + 1);
}
cout << res;
return 0;
}
🐖:while (j < i && s[q[i]] > 1) s[q[j ++ ]] – ; 里可以不加 j<i 的原因:因为当j > i时,所有s[]必然是0,此时循环中的第二个条件一定不成立。