双指针扩展-三指针笔记

双指针扩展-三指针笔记

在使用双指针维护一段序列时,可能会出现多个区间的情况,这时若是仅采用双指针移动,则会漏掉部分情况

可以再加入一个指针来,使两个指针维护一个子序列,使子序列和另外一个指针共同维护

这里以洛谷P1102为例:

我们需要对一段序列求满足条件的数对的数量,但由于序列中元素可以重复,所以两个快慢指针会漏掉一部分情况:

2 2 3 3 4 5 5 5 6 7

假设 \(i\) 指针和 \(j\) 指针从头开始,当我们计算的 \(A-B=C=3\) 时,数对数加一。

for (int i = 1, j=1; i <= n; i++) {
while (i >= j && a[i] - a[j] >= c) {//保证i在j前面
j++;
if (a[i] - a[j] == c) ans++;
}
}

\(i\) 运动到第一个 \(5\) 时,满足要求,此时移动 \(j\) 到第二个 \(2\),再次满足要求,在移动 \(j\) 指向 \(3\)不满足要求

\(i\) 移动,但是会发现 \(i\) 仍然指向的是 \(5\)\(j\)移动出了 \(2\) 所在的区间,则答案会丢失一部分

采用三指针维护:

for (int i = 1, j1 = 1, j2 = 1; i <= n; i++) {
while (i >= j1 && a[i] - a[j1] >= c)
j1++;
while (i >= j2 && a[i] - a[j2] > c)
j2++;
ans += j1 - j2;
}

我们让 \(j_1\) 这个指针指向满足 \(A-B=C=3\) 时,\(j\) 序列的最后元素的下一个元素,即指向 \(2\) 之后的 \(3\)\(j_2\) 指向 \(j\) 序列的第一个元素,即指向第一个 \(2\)

ps:

a[i] - a[j1] >= c 可移项为 a[j1] <= a[i] - c
a[i] - a[j2] > c 可移项为 a[j2] < a[i] - c
可以看出在有序数列中 j2是小于j1

这时 \(j_1-j_2\) 就是 \(j\) 序列的长度,随后移动 \(i\) 指针,直到移动出 \(5\) 的区间,\(ans\) 每次都加上 \(j\) 序列的长度,保证不漏

完整代码:

#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
int a[200010];
int n, c;
long long ans;
int main()
{
scanf("%d %d", &n, &c);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
for (int i = 1, j1 = 1, j2 = 1; i <= n; i++) {
while (i >= j1 && a[i] - a[j1] >= c)
j1++;
while (i >= j2 && a[i] - a[j2] > c)
j2++;
ans += j1 - j2;
}
printf("%lld", ans);
return 0;
}
posted @   才瓯  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示