双指针技巧
面试官问:"如何在 O(n) 时间内,在一个升序数组中找到两个数,使它们的和等于 target?"
候选人小赵秒答:"用哈希表,遍历一次,记录每个数需要的另一个数。"
面试官点点头:"空间复杂度能做到 O(1) 吗?"
小赵愣了一下,说:"那...只能用暴力解法 O(n²) ..."
面试官追问:"你再想想,有没有不需要额外空间的做法?"
小赵陷入沉思。
【直观类比】
双指针就像两人从房子两端向中间走:
- 你站在门口,朋友站在窗户边
- 你们同时向对方走去
- 每走一步,互相通报看到了什么
- 直到两人相遇,或者找到了目标
这就是双指针的核心思想——利用数组的物理结构,用两个指针从不同方向夹逼。
一、问题的引入
经典题:两数之和(LeetCode 167)
哈希表解法:O(n) 时间,O(n) 空间
双指针解法:O(n) 时间,O(1) 空间
二、双指针的三种类型
2.1 碰撞指针(左右夹逼)
适用场景:有序数组、字符串
模板:
2.2 快慢指针(同向而行)
适用场景:链表、数组
模板:
2.3 左右指针(两端出发)
适用场景:反转数组、回文判断
模板:
三、实战:LeetCode 15 三数之和 🔴
题目:
示例:
解题思路:
关键点:
- 先排序:
O(n log n),为双指针创造条件 - 固定一个数,再用双指针找另外两个
- 去重是难点,也是面试官追问的点
四、实战:LeetCode 142 环形链表 II 🔴
题目:
普通解法:用 HashSet 记录访问过的节点
快慢指针解法:O(1) 空间
数学证明:
- 慢指针走了
f + a - 快指针走了
f + a + n(多走了一整圈) - 快指针速度是慢指针的 2 倍:
2(f + a) = f + a + n→f = n - a
五、实战:删除链表倒数第 N 个节点 🔴
题目:LeetCode 19
六、常见题型总结
七、记忆技巧
双指针的三口诀:
"碰撞指针左右走,有序数组夹逼求" "快慢指针同向跑,链表环检测最妙" "头尾指针向中靠,数据反转回文找"
八、实战检验
检验一:LeetCode 11 容器盛水问题
考点:碰撞指针 + 贪心(移动较小边)。
检验二:LeetCode 234 回文链表
考点:快慢指针找中点 + 反转链表 + 比较。
九、总结
双指针是一种利用数据结构物理特性的算法技巧:
- 有序数组 → 用碰撞指针,从两端向中间夹逼
- 链表 → 用快慢指针,一个走快点、一个走慢点
- 反转操作 → 用左右指针,从两端交换
记住:双指针的核心是用空间换时间,或者说是"利用已知条件减少遍历"。