双指针是用两个下标变量配合逻辑判断的自然选择,非固定模板;适用于有序数组、原地操作等场景,不适用于需随机访问或数据无序的情况。

双指针不是模板,是数组下标配合逻辑的自然选择
双指针在 C++ 里没有专用语法或函数——它只是用两个 int 变量(比如 left 和 right)分别指向数组不同位置,靠移动它们来避免嵌套循环。关键不在“指针”二字,而在你是否需要同时观察/比较/收缩两个端点。
常见错误是硬套“快慢指针”或“左右指针”名字:比如该用单循环+哈希的去重问题,强行上双指针反而写错边界;又或者对已排序数组做两数之和时,不用双指针而写 O(n²) 暴力。
- 适用场景:输入有序、需原地操作、目标可由两端推导(如和、最大面积、回文判断)
- 不适用场景:需随机访问中间元素、依赖元素值以外的上下文(如前缀和)、数据无序且不可排序
-
vector和裸int*数组都能用,但注意vector.size()返回size_t,和int混用可能触发隐式转换警告
左右指针收缩时,移动哪边?看条件而非固定套路
比如找两数之和等于 target:当 nums[left] + nums[right] > target,必须动 right(减小和);反之动 left(增大和)。这里没有“默认先动左”的规则,全由当前计算结果决定。
容易踩的坑是写成 if (sum 而忽略相等时的退出逻辑——漏掉 <code>== 分支会导致死循环或跳过解。
立即学习“C++免费学习笔记(深入)”;
- 每次只移动一个指针,除非明确需要跳过重复值(如三数之和去重)
- 移动后立即检查越界:
while (left 这类去重必须在移动后、下次计算前做 - 用
还是 <code> 判定循环?取决于区间定义:闭区间 [<code>left,right] 用left ;半开区间 [<code>left,right) 用left
快慢指针处理链表环时,C++ 要小心迭代器失效和 nullptr 解引用
虽然标题说“数组”,但很多人搜“双指针”实际想解决链表环检测(ListNode* 场景)。这时 slow 走一步、fast 走两步,核心是判断 fast == nullptr || fast->next == nullptr 再前进。
典型错误是在 while 条件里只写 fast != nullptr,然后直接用 fast = fast->next->next,导致访问空指针成员。
- 安全写法:
while (fast != nullptr && fast->next != nullptr),再执行fast = fast->next->next - 找到环入口时,不能直接返回
slow,要另起一个指针从头走,和slow同速相遇才是入口节点 - 数组模拟链表(如题目给索引数组
nums[i]表示 next)时,仍需按链表逻辑判空,别当成普通数组下标用
std::array 或 vector 用双指针,别忘了 size() 是无符号类型
写 int left = 0, right = nums.size() - 1; 看似没问题,但如果 nums 为空,nums.size() - 1 会变成极大正数(size_t 下溢),导致 right 变成 0xffffffff,循环直接崩溃或行为异常。
这不是编译错误,是运行时未定义行为,调试时极难定位。
- 正确做法:声明为
size_t left = 0, right = nums.size();,循环条件改用left ,访问时用 <code>nums[left]和nums[right-1] - 或者统一转成有符号:
auto n = static_cast<int>(nums.size());</int>,但要注意n是否超 int 范围(一般不会) - 用
at()替代[]可捕获越界异常,但仅用于调试,别留到生产环境
真正麻烦的从来不是怎么写双指针,而是想清楚:当前问题中,两个下标代表什么语义?它们的移动是否覆盖所有必要状态?边界缩小时有没有漏掉某个合法解?这些没法靠模板解决。










