双指针思想介绍
双指针(Two Pointers)是一种在数组或链表等线性结构中常用的算法技巧,通过使用两个指针(索引或引用)以不同的速度或方向遍历数据结构,从而高效解决问题。双指针通常用于优化暴力解法,将时间复杂度从 O(n²) 降低到 O(n) 或 O(n log n)。
常见应用场景:
- 快慢指针:用于链表中的环检测、找中点等(如快指针每次走两步,慢指针走一步)。
- 左右指针:用于有序数组的两数之和、反转数组等(如一个指针从左向右,另一个从右向左)。
- 滑动窗口:通过调整两个指针的间隔解决子数组/子串问题(如最小覆盖子串)。
蓝桥杯中的双指针题目示例
以下是蓝桥杯竞赛中可能用到双指针思想的题目及其解法思路:
1. 两数之和(有序数组)
- 题目描述:给定一个升序排列的数组和一个目标值,找到数组中两个数的和等于目标值,返回它们的索引。
- 双指针解法:
- 初始化左指针
left = 0
,右指针right = len(nums) - 1
。 - 比较
nums[left] + nums[right]
与目标值:- 若和等于目标值,返回结果;
- 若和小于目标值,
left++
(需要更大的数); - 若和大于目标值,
right--
(需要更小的数)。
- 初始化左指针
- 时间复杂度:O(n)。
def twoSum(nums, target):left, right = 0, len(nums) - 1while left < right:s = nums[left] + nums[right]if s == target:return [left, right]elif s < target:left += 1else:right -= 1return []
2. 三数之和(去重)
- 题目描述:找到数组中所有不重复的三元组,满足
a + b + c = 0
。 - 双指针解法:
- 先排序数组,固定一个数
nums[i]
,然后用双指针在i+1
到末尾寻找两数之和等于-nums[i]
。 - 需跳过重复值以避免重复解。
- 先排序数组,固定一个数
- 时间复杂度:O(n²)。
python
复制
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) - 1while left < right:s = nums[i] + nums[left] + nums[right]if s < 0:left += 1elif s > 0:right -= 1else: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 += 1right -= 1return res
3. 盛最多水的容器(贪心+双指针)
- 题目描述:给定一个数组表示容器的高度,找到两条线使得它们与 x 轴构成的容器能装最多的水。
- 双指针解法:
- 初始化
left = 0
,right = len(height) - 1
,max_area = 0
。 - 每次移动较短的边(因为移动长边不可能增加面积)。
- 初始化
- 时间复杂度:O(n)。
python
复制
def maxArea(height):left, right = 0, len(height) - 1max_area = 0while left < right:area = (right - left) * min(height[left], height[right])max_area = max(max_area, area)if height[left] < height[right]:left += 1else:right -= 1return max_area
4. 蓝桥杯真题示例:日志统计(滑动窗口)
- 题目链接:蓝桥杯 2018 省赛
- 问题描述:给定 N 条日志的点赞时间,统计在任意长度为 D 的时间段内点赞不少于 K 次的帖子。
- 双指针解法:
- 按时间排序后,用滑动窗口(双指针)统计窗口内的点赞数,若满足条件则标记帖子。
- 代码片段:
python
复制
logs = [...] # 日志数据格式: [(时间, 帖子id), ...] logs.sort() count = {} # 记录当前窗口内各id的点赞数 res = set() left = 0 for right in range(len(logs)):id = logs[right][1]count[id] = count.get(id, 0) + 1while logs[right][0] - logs[left][0] >= D:count[logs[left][1]] -= 1left += 1if count[id] >= K:res.add(id)
总结
双指针的核心是通过协同移动两个指针减少不必要的计算,常用于:
- 有序数组的搜索(如两数之和)。
- 滑动窗口问题(如子串、区间统计)。
- 链表操作(如快慢指针)。
在蓝桥杯竞赛中,双指针常与排序、贪心等结合,需注意边界条件和去重处理。