双指针算法involves using two pointers to solve a problem, usually to search for a pair of elements or to traverse the data structure. 这种技巧可以大大提高算法的效率,通常可以将时间复杂度从 O(n^2) 降低到 O(n)。
2. 双指针的常见类型
2.1 对撞指针
两个指针分别从数组的两端向中间移动。
应用场景:
有序数组的 Two Sum 问题
回文串判断
示例:有序数组的 Two Sum(LeetCode 167)
1 2 3 4 5 6 7 8 9 10 11
deftwoSum(numbers, target): left, right = 0, len(numbers) - 1 while left < right: current_sum = numbers[left] + numbers[right] if current_sum == target: return [left + 1, right + 1] # 题目要求索引从1开始 elif current_sum < target: left += 1 else: right -= 1 return [] # 没有找到符合条件的两个数
2.2 快慢指针
两个指针从同一端出发,但是移动速度不同。
应用场景:
链表中环的检测
寻找链表的中点
删除链表的倒数第 N 个节点
示例:链表中环的检测(LeetCode 141)
1 2 3 4 5 6 7 8 9 10 11
defhasCycle(head): ifnot head ornot head.next: returnFalse slow = head fast = head.next while slow != fast: ifnot fast ornot fast.next: returnFalse slow = slow.next fast = fast.next.next returnTrue
2.3 滑动窗口
一左一右两个指针构成一个窗口,滑动遍历整个数组或字符串。
应用场景:
子串问题
子数组问题
示例:无重复字符的最长子串(LeetCode 3)
1 2 3 4 5 6 7 8 9 10 11
deflengthOfLongestSubstring(s): char_index = {} max_length = 0 start = 0 for end, char inenumerate(s): if char in char_index and char_index[char] >= start: start = char_index[char] + 1 else: max_length = max(max_length, end - start + 1) char_index[char] = end return max_length
3. 双指针解题技巧
3.1 合并两个有序数组
LeetCode 88: Merge Sorted Array
1 2 3 4 5 6 7 8 9 10
defmerge(nums1, m, nums2, n): p1, p2, p = m - 1, n - 1, m + n - 1 while p2 >= 0: if p1 >= 0and nums1[p1] > nums2[p2]: nums1[p] = nums1[p1] p1 -= 1 else: nums1[p] = nums2[p2] p2 -= 1 p -= 1
3.2 删除排序数组中的重复项
LeetCode 26: Remove Duplicates from Sorted Array
1 2 3 4 5 6 7 8 9
defremoveDuplicates(nums): ifnot nums: return0 slow = 0 for fast inrange(1, len(nums)): if nums[fast] != nums[slow]: slow += 1 nums[slow] = nums[fast] return slow + 1
defthreeSum(nums): nums.sort() result = [] for i inrange(len(nums) - 2): if i > 0and nums[i] == nums[i-1]: continue left, right = i + 1, len(nums) - 1 while left < right: total = nums[i] + nums[left] + nums[right] if total == 0: result.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 elif total < 0: left += 1 else: right -= 1 return result
3.4 盛最多水的容器
LeetCode 11: Container With Most Water
1 2 3 4 5 6 7 8 9 10 11
defmaxArea(height): left, right = 0, len(height) - 1 max_area = 0 while left < right: area = min(height[left], height[right]) * (right - left) max_area = max(max_area, area) if height[left] < height[right]: left += 1 else: right -= 1 return max_area