双指针算法
双指针算法的核心思想就是优化,主要是优化时间复杂度,可以将朴素算法优化至O(n)的时间复杂度。
最长连续不重复子序列
题意大致是给你一串序列,让你求它的最长连续不包含不重复字符的子序列的长度。
这是一道双指针算法的模板题。
首先是用i来从0
到n - 1
的枚举,用来j表示距离i最左边的位置,使得i和j之间的子序列没有重复数字,显然i <= j
。当i枚举到n - 1
后,就可以得到res
了。
其次,i和j之间具有单调性,即当i增加一位的时候,j不增加或者增加,不可能减小。当i增加一位时,序列中可能会出现重复字符。如果出现重复字符,必定是i指向的字符出现了重复,此时j往后移,直至i指向的字符不再重复出现。
我们用st[ ]数组存储每个字符出现的次数,当st[i] > 1
时,说明这个字符重复出现了。
举个例子如下:
具体代码如下:
//当i确定时,j最多往左到什么地方,得满足中间序列没有重复元素
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n, res;
int num[N], st[N]; //st记录区间内数据出现的次数
int main()
{
cin >> n;
for(int i = 0; i < n; i ++)
cin >> num[i];
for(int i = 0, j = 0; j < n; j ++)
{
st[num[j]] ++; //一进入区间就给它出现的次数加一
while(i <= j && st[num[j]] > 1) //这里的i <= j可以不用写,因为i必定小于等于j
{
st[num[i]] --; //离开区间就给它出现的次数减一
i ++; //离开区间
}
res = max(res, j - i + 1); //更新res的值
}
cout << res << endl;
return 0;
}
题意:两组数(a[N], b[N])
,从中分别选一个数相加等于一个规定的常数x
。
这道题也挺简单,也是模板题。
使用两个指针i和j,i从头到尾遍历a数组,j从尾到头遍历b数组。
如果a[i] + b[j] > x
,说明b[j]
大了,得j --
如果a[i] + b[j] < x
,说明a[i]
小了,得i ++
如果相等,就直接输出。然后i ++
,进行下一轮匹配。
举个例子如下:
具体见代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n, m, x;
int a[N], b[N];
int main()
{
cin >> n >> m >> x;
for(int i = 0; i < n; i ++)
scanf("%d", & a[i]);
for(int j = 0; j < m; j ++)
scanf("%d", & b[j]);
for(int i = 0, j = m - 1; i < n && j >= 0; i ++)
{
while(a[i] + b[j] > x) //大于
j --;
if(a[i] + b[j] < x) //小于
continue;
printf("%d %d\n", i, j); //这里不用判断条件,因为能走到这里肯定是相等的
j --;
}
return 0;
}