双指针算法
Posted thesunandsnow
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双指针算法相关的知识,希望对你有一定的参考价值。
对于两重for循环
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
{
//具体代码
}//O(n^2)
双指针算法的思想就是:寻找指针i 与 j 之间是否有单调的关系。若存在,则利用此关系来把整个枚举的状态数量从O(n^2)降到O(n),模板如下
for(int i = 0, j = 0; i < n; ++i)
{
while(j < i && check(j, i)) ++j;//此行为降低时间复杂度的关键。check()函数反映指针i与j的性质
//每道题目的具体逻辑
}
最典型的应用如下:
给你一个英文字符串,找到每一个单词并逐行输出
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
/**
* 把一个字符串中的所有单词找到,并按行输出
* */
int main()
{
char str[100];
gets(str);
int n = strlen(str);
for(int i = 0; i < n; ++i) cout << str[i];
cout << '
';
for(int i = 0; i < n; ++i)
{
int j = 0;
while(j < i && str[j] != ' ') ++j;
//双指针算法的具体逻辑部分
for(int k = i; k < j; ++k)
printf("%c", str[k]);
cout << '
';
}
}
当然了,往往会卡在这个j与i指针之间的关系并不好找
最长连续不重复子序列
给定一个长度为n的整数序列,请找出最长的不包含重复数字的连续区间,输出它的长度。
输入格式
第一行包含整数n。
第二行包含n个整数(均在0~100000范围内),表示整数序列。
输出格式
共一行,包含一个整数,表示最长的不包含重复数字的连续子序列的长度。
数据范围
1≤n≤100000
具体解题思路:运用桶排思想,用数组s[]来记录每个输入的数字a[i]出现的次数,当s[a[i]]出现的次数大于1时,[j, i]区间构成的子序列就必定有重复元素,因此我们只能通过右移j指针,来试图在[j, i]区间中找到这个重复的元素并将其排除(s[a[i]]--; ++j;)每次j指针右移我们都需要检查一下s[a[i]]是否已经等于1(数字a[i]是否仅在新的区间[j, i]中出现一次)来判断是否停止移动j指针
具体代码如下
#include <iostream>
#include <string>
using namespace std;
const int N = 100010;
int n;
int a[N], s[N];//桶排序思想,当数据范围过大时应该用哈希表来求解
int main()
{
ios::sync_with_stdio(false);
cin >> n;
for(int i = 0; i < n; ++i) cin >> a[i];
int len = 0;//记录最长连续子序列
for(int i = 0, j = 0; i < n; ++i)
{
s[a[i]]++;
while(/*j <= i&& 没必要写*/s[a[i]] > 1)//当s[a[i]]出现的次数大于1时,[j, i]区间构成的子序列就必定有重复元素
{
s[a[j]]--;
j++;
}
len = max(len, i - j + 1);
}
cout << len << endl;
}
声明:acWing课程学习总结
作者:DriftingAE86
以上是关于双指针算法的主要内容,如果未能解决你的问题,请参考以下文章