概述
双指针法通过维护两个指针高效解决数组/链表问题,主要分为:
- 同向指针(快慢指针)
- 相向指针(左右指针)
- 滑动窗口(特殊双指针)
适用于处理有序数组、子数组问题,时间复杂度通常为O(n)
283.移动零
题目特征
- 保持非零元素相对顺序
- 原地操作(不能新建数组)
- 最小操作次数
双指针解法
关键思想:快指针扫描非零元素,慢指针标记填充位置
算法步骤:
- 初始化慢指针slow=0
- 快指针fast遍历数组:
- 当nums[fast]非零时,与nums[slow]交换
- slow前进
- 遍历结束后,slow之后的位置置零(可优化为直接覆盖)
示例说明:
输入:[0,1,0,3,12]
过程演示:
fast=0(0跳过) → fast=1(1交换到0位) → fast=2(0跳过) →
fast=3(3交换到1位) → fast=4(12交换到2位)
最终结果:[1,3,12,0,0]
复杂度分析:
- 时间复杂度:O(n)
- 空间复杂度:O(1)
def moveZeroes(nums):
slow = 0
for fast in range(len(nums)):
if nums[fast] != 0:
nums[slow], nums[fast] = nums[fast], nums[slow]
slow += 1
11.盛水最多的容器
题目特征
-
寻找最大矩形面积
-
高度由短板决定
-
需要高效扫描方法
双指针解法
关键思想:从两端向中间收敛,每次移动较矮的边
算法步骤:
1.初始化left=0, right=len(height)-1
2.计算当前面积并更新最大值
3.移动高度较小的一侧指针
4.重复直到指针相遇
正确性证明:
移动较高边:宽度减小,高度不会超过原短板,面积必然减小
移动较低边:可能获得更高短板,存在更大面积的可能性
复杂度分析:
-
时间复杂度:O(n)
-
空间复杂度:O(1)
def maxArea(height):
left, right = 0, len(height)-1
max_water = 0
while left < right:
h = min(height[left], height[right])
max_water = max(max_water, h*(right-left))
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_water
15.三数之和
题目特征
- 需要去重
- 组合问题
- 时间复杂度优化要求
排序+双指针
解题框架:
- 数组排序(O(nlogn))
- 遍历固定第一个数nums[i]
- 在i+1到末尾区间使用双指针找两数之和为-nums[i]
去重策略:
- 当nums[i] == nums[i-1]时跳过(i>0)
- 找到解后,跳过left右侧相同值
- 找到解后,跳过right左侧相同值
示例说明:
输入:[-1,0,1,2,-1,-4]
过程演示:
排序后:[-4,-1,-1,0,1,2]
i=0时,在[-1,-1,0,1,2]中找两数之和为4
复杂度分析:
- 时间复杂度:O(n)
- 空间复杂度:O(1)
def threeSum(nums):
nums.sort()
res = []
for i in range(len(nums)-2):
if i>0 and nums[i]==nums[i-1]:
continue
left, right = i+1, len(nums)-1
while left < right:
s = nums[i]+nums[left]+nums[right]
if s < 0:
left +=1
elif s >0:
right -=1
else:
res.append([nums[i],nums[left],nums[right]])
while left<right and nums[left]==nums[left+1]:
left +=1
while left<right and nums[right]==nums[right-1]:
right -=1
left +=1
right -=1
return res
42.接雨水
题目特征
- 立体图形计算
- 需要考虑左右边界
- 多种解法比较(动态规划、单调栈、双指针
双指针优化解法
核心思路:维护左右最大高度,每次处理较小的一侧
算法步骤:
- 初始化left=0, right=len(height)-1
- 维护left_max和right_max
- 比较height[left]和height[right]:
- 左较小:计算左指针处水量,移动左指针
- 右较小:计算右指针处水量,移动右指针
正确性解释:
当height[left] < height[right]时,left_max是可信的短板
水量由left_max - height[left]决定
复杂度分析:
- 时间复杂度:O(n)
- 空间复杂度:O(1)
def trap(height):
left, right = 0, len(height)-1
left_max = right_max = water = 0
while left < right:
if height[left] < height[right]:
left_max = max(left_max, height[left])
water += left_max - height[left]
left +=1
else:
right_max = max(right_max, height[right])
water += right_max - height[right]
right -=1
return water
总结与题型特征
双指针适用场景
题型 | 特征 | 指针类型 |
---|---|---|
元素移动 | 保持顺序,原地操作 | 快慢指针 |
有序数组组合 | 需要避免暴力枚举 | 相向指针 |
容器类问题 | 面积/容量计算 | 相向指针 |
多条件约束问题 | 需要同时满足多个条件 | 多指针组合 |
解题技巧
- 先尝试排序(需要考虑时间复杂度)
- 画图辅助理解
- 注意去重条件以及边界处理
- 分析指针移动的单调性