双指针
双指针又称尺取法,是一种常用的算法技巧,可以用来解决序列的区间问题。
双指针的基本思想:
两个指针
- 反向扫描:
方向相反, 从前往后扫描, 从后往前扫描,在中间相会。 - 同向扫描:
方向相同,都从前往后扫描,可以让 跑在 的前面。
同向扫描的两个指针又称为快慢指针,快慢指针在序列上产生一个大小可变的滑动窗口,应用非常广泛。
双指针应用
洛谷 P1147. 连续正整数和
题目描述
给定一个正整数
例如,
输入格式
输入一行一个正整数,表示
输出格式
输出每行包含两个正整数,表示一个满足条件的连续正整数段的左右端点,两数之间用一个空格隔开。
输出按左端点大小升序排列。
分析
把自然数看作一个升序序列,让
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n; cin >> n;
int i = 1, j = 1, s = 1;
while (i <= n / 2) {
if (s < n) {
j++;
s +=j ;
} else {
if (s == n) cout << i << " " << j << endl;
s -= i;
i++;
}
}
return 0;
}洛谷 P1102. A - B 数对
题目描述
给出一串正整数数列以及一个正整数
输入格式
输入共两行。
第一行,两个正整数
第二行,
输出格式
一行,表示该串正整数中包含的满足
分析
将数列升序排序。
设
枚举
代码
#include <bits/stdc++.h>
using namespace std;
int n, C, a[200010];
int main() {
cin >> n >> C;
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + 1 + n);
long long ans = 0;
int i = 1, j = 1;
for (int k = 1; k <= n; k++) {
while (i <= n && a[i] - a[k] < C) i++;
while (j <= n && a[j] - a[k] <= C) j++;
ans += j - i;
}
cout << ans << endl;
return 0;
}洛谷 P1638. 逛画展
题目描述
博览馆正在展出由世上最佳的
游客在购买门票时必须说明两个数字,
Sept 希望入场后可以看到所有名师的图画。当然,他想最小化购买门票的价格。
请求出他购买门票时应选择的
若存在多组解,输出
输入格式
第一行两个整数
第二行包含
输出格式
一行两个整数
分析
设
- 如果当前区间内的画家数量
,则 j++; cnt[a[j]]++; if (cnt[a[j]] == 1) num++; - 如果当前区间内的画家数量
,则比较 与当前区间长度,更新 与 。 cnt[a[i]]--; if (cnt[a[i]] == 0) num--; i++;
代码
#include <bits/stdc++.h>
using namespace std;
int n, m, a[100010], cnt[2010];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
int i = 1, j = 1, num = 1, len = 1e9, l = -1, r = -1;
cnt[a[1]]++;
while (j <= n) {
if (num < m) {
j++;
cnt[a[j]]++;
if (cnt[a[j]] == 1) num++;
} else if (num == m) {
if (len > j - i + 1) {
len = j - i + 1;
l = i;
r = j;
}
cnt[a[i]]--;
if (cnt[a[i]] == 0) num--;
i++;
}
}
cout << l << " " << r << endl;
return 0;
}