双指针扩展-三指针笔记
双指针扩展-三指针笔记
在使用双指针维护一段序列时,可能会出现多个区间的情况,这时若是仅采用双指针移动,则会漏掉部分情况
可以再加入一个指针来,使两个指针维护一个子序列,使子序列和另外一个指针共同维护
这里以洛谷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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具