双指针
- 常见问题分类:
- 对于一个序列,用两个指针维护一段区间
- 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
基本模版
for (int i = 0, j = 0; i < n; i ++ )
{
while (j < i && check(i, j)) j ++ ;
// 填充具体问题的逻辑
}
求最大不重复子序列
开一个cnt数组,计数排序 两个指针i,j从头开始,cnt[a[i]]++ cnt如果是2了,就开始j++,直到cnt恢复到1 res更新,max(i-j+1,res)
#include <algorithm>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N];
int cnt[N];
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int res = 0;
for (int i = 0, j = 0; i < n; i++) {
cnt[a[i]]++;
while (i > j && cnt[a[i]] > 1)
cnt[a[j++]]--;
res = max(res, i - j + 1);
}
printf("%d", res);
return 0;
}
两个序列a,b,求a[i]+b[j] == k的序列对(i,j)
对于两个序列,如果循环两遍暴力o(n^2)
两个指针 i:n-1,j:0; 注意要留意i,j不为负
#include <algorithm>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int n, m, k;
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
for (int i = 0; i < m; i++)
scanf("%d", &b[i]);
for (int i = n - 1, j = 0; i >= 0 && j < m; j++) {
while (i >= 0 && a[i] + b[j] > k)
i--;
if (i>=0&&a[i] + b[j] == k)
printf("%d %d\n", i, j);
}
return 0;
}
判断a是b的子序列
两个指针i,j 如果a[i] == b[j],i++ j一直往后移动
#include <algorithm>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int n, m;
int main()
{
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
for (int i = 0; i < m; i++)
scanf("%d", &b[i]);
int i = 0,j = 0;
while(i<n&&j<m){
if(a[i] == b[j]) i++;
j++;
}
if (i == n)
puts("Yes");
else
puts("No");
return 0;
}