算法基础1.5双指针算法

前言

双指针算法其实在前面已经用过很多次了,需要注意的是,这里的“双指针”并不是说用两个指针,而是使用“指针”这个抽象的思想,比如用一个变量也可以作为指针。

指针最常见的作用就是将一个需要嵌套循环的代码(时间复杂度为O(n^2))变成一个单循环的代码(时间复杂度是x*n,即O(n))。我们本来是两个变量ij嵌套循环各n次,现在我们通过挖掘两者在题目中的关系,来减少一些无用的i``j组合

该节里面讲了道题作为引导

正文

题目与代码

image-20230311151732348

代码如下

#include <iostream> using namespace std; const int N = 100010; int n; int q[N], s[N]; int main() { scanf("%d", &n); for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]); // 记录区间长度 int res = 0; for (int i = 0, j = 0; i < n; i ++ ) { // i移动,记录区间中新增的数 s[q[i]] ++ ; // 如果某一个数出现的次数超过1次(其实只能是2次),那么j开始移动 // s[q[j ++ ]] --这个语句先让s[q[j]]--,然后再j+1 while (j < i && s[q[i]] > 1) s[q[j ++ ]] -- ; // 看看更新后区间有没有变长 res = max(res, i - j + 1); } cout << res << endl; return 0; }

分析

这道题我们使用双指针,i指向这个最长序列的最右端,他是一个遍历的指针,j指向这个最长序列的最左端,他是一个依赖于i而变化的指针。如此,j就不需要进行嵌套循环了,他只需要在特定条件下变化即可。

先明确大体思路:一开始两个指针都指向了数组第0位,然后i开始向右移动,j不动。直至i``j两个指针夹着的这个区间中出现了重复的数,那么i不动,j开始移动,一直移动到区间内再次没有重复的数(实际上i结束移动说明现在i指向的那个数就是这个区间中某一个数的第二份,所以j停止移动的节点就是移动到这个数第一次出现的位置的后面一位)。

大体思路定下来了,最后只要实现一下记录区间中有哪些数这一功能即可,这个单独在创建一个数组即可,他的x位上的数值就代表当前区间中x这个数出现的次数。每次i移动都会让某一位置+1,而j每次移动都会让某一个位置-1。

注意res的更新要让当前值与原先值作比较取最大值,因为更新后有可能长度变短。

结语

大体思路就是:先通过暴力的思路写出来代码,然后思考其中两个变量之间的线性关系,通过这种关系将时间复杂度从O(n^2)降到O(n)


__EOF__

本文作者Zaughter
本文链接https://www.cnblogs.com/zaughtercode/p/17229488.html
关于博主:qq:1730119093 欢迎加我讨论
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Zaughter  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示