双指针的常见用法及适用场景详解
双指针是算法中一种高效且灵活的解题技巧,通过两个指针的协同操作降低时间复杂度和空间复杂度。以下是双指针的核心用法及适用场景分析:
一、对撞指针(反向双指针)
核心思想:两个指针分别从序列的两端向中间移动,适用于有序数组或可通过排序转化为有序的问题。
在反向双指针里面right指向的是数组的长度,在循环的时候直接while(left < right) { }统一下
• 典型应用:
- 两数之和/三数之和
◦ 题号:167. 两数之和 II、15. 三数之和
◦ 方法:固定一个数,用双指针在剩余区间内寻找目标值。 - 回文判断
◦ 题号:125. 验证回文串
◦ 方法:头尾指针比较字符是否对称。 - 盛最多水的容器
◦ 题号:11. 盛最多水的容器
◦ 方法:左右指针向中间移动,保留较高边以最大化容积。
• 特点:时间复杂度为 O(n),空间复杂度 O(1)。
二、快慢指针(同向双指针)
核心思想:两个指针同向移动但速度不同,用于链表操作或数组去重。
• 典型应用:
- 链表环检测
◦ 题号:141. 环形链表
◦ 方法:快指针每次走两步,慢指针走一步,相遇则有环。 - 链表中间节点查找
◦ 题号:876. 链表的中间结点
◦ 方法:快指针到末尾时,慢指针指向中点。 - 数组去重/删除元素
◦ 题号:26. 删除有序数组重复项、27. 移除元素
◦ 方法:慢指针标记有效位置,快指针遍历数组。
• 特点:时间复杂度 O(n),空间复杂度 O(1)。
三、分离双指针(多序列处理)
核心思想:两个指针分别属于不同序列(如两个数组或链表),用于合并、交集问题。
• 典型应用:
- 合并两个有序数组
◦ 题号:88. 合并两个有序数组
◦ 方法:从后向前比较元素,避免覆盖原数组。 - 两个数组的交集
◦ 题号:349. 两个数组的交集
◦ 方法:排序后双指针遍历比较元素。 - 归并有序链表
◦ 题号:21. 合并两个有序链表
◦ 方法:比较两个链表头节点,依次合并。
• 特点:时间复杂度 O(m + n),空间复杂度 O(1)。
四、滑动窗口(特殊双指针)
核心思想:两个指针定义窗口的左右边界,动态调整窗口大小寻找连续子区间的最优解。
• 典型应用:
- 最长无重复子串
◦ 题号:3. 无重复字符的最长子串
◦ 方法:右指针扩展窗口,左指针收缩。 - 最小覆盖子串
◦ 题号:76. 最小覆盖子串
◦ 方法:统计目标字符频率,动态调整窗口。
• 特点:时间复杂度 O(n),空间复杂度 O(k)(k 为字符集大小)。
五、不同双指针的适用场景对比
类型 | 适用场景 | 时间复杂度 | 空间复杂度 | 典型问题 |
---|---|---|---|---|
对撞指针 | 有序数组求和、回文判断、容器容积问题 | O(n) | O(1) | [两数之和 II] |
快慢指针 | 链表环检测、数组去重、链表中点查找 | O(n) | O(1) | [环形链表] |
分离双指针 | 多序列合并、交集、差异比较 | O(m + n) | O(1) | [合并两个有序数组] |
滑动窗口 | 连续子序列最值、字符串覆盖问题 | O(n) | O(k) | [最小覆盖子串] |
总结
双指针的核心优势在于通过指针的协同操作将时间复杂度从 O(n²) 优化至 O(n),适用于线性数据结构(数组、链表、字符串)的多种场景。具体选择哪种双指针需结合问题特征:
• 有序数组优先考虑对撞指针;
• 链表操作优先使用快慢指针;
• 多序列处理选择分离双指针;
• 连续子序列问题采用滑动窗口。