双指针算法是一种常用的算法技巧,通过使用两个指针在数据结构(如数组、链表等)中协同工作,来解决一些特定问题。它的核心思想是通过指针的移动来减少时间复杂度,通常用于优化暴力解法。
数组或链表中的遍历:
滑动窗口:
快慢指针:
有序数组的两数之和:
指针的初始化:
指针的移动规则:
终止条件:
以下是双指针算法的通用流程图,使用 Mermaid 语法绘制:
流程图说明
检查当前指针是否满足终止条件(如相遇、超出范围等)。
如果满足,则算法结束。
如果不满足,则继续执行。
时间复杂度优化:
空间复杂度低:
代码简洁:
边界条件:
移动规则:
终止条件:
双指针算法是一种高效的算法技巧,常用于解决数组、链表等问题。以下是几个经典的双指针算法示例及其 Python 实现代码。
给定一个升序排列的数组和一个目标值,找到数组中两个数的和等于目标值,并返回它们的索引。
def two_sum(nums, target):
left, right = 0, len(nums) - 1 # 初始化左右指针
while left < right:
current_sum = nums[left] + nums[right]
if current_sum == target:
return [left, right] # 找到结果
elif current_sum < target:
left += 1 # 和太小,左指针右移
else:
right -= 1 # 和太大,右指针左移
return [] # 未找到结果
# 示例
nums = [2, 7, 11, 15]
target = 9
print(two_sum(nums, target)) # 输出: [0, 1]
给定一个升序排列的数组,原地移除重复的元素,并返回新数组的长度。
初始化两个指针,一个慢指针(slow),一个快指针(fast)。
快指针遍历数组,慢指针记录不重复元素的位置。
当快指针指向的元素与慢指针指向的元素不同时,将快指针的元素复制到慢指针的下一个位置。
最后返回慢指针的位置加 1,即为新数组的长度。
def remove_duplicates(nums):
if not nums:
return 0
slow = 0 # 慢指针
for fast in range(1, len(nums)): # 快指针
if nums[fast] != nums[slow]:
slow += 1
nums[slow] = nums[fast]
return slow + 1 # 新数组的长度
# 示例
nums = [1, 1, 2, 2, 3, 4, 4, 5]
length = remove_duplicates(nums)
print("新数组长度:", length) # 输出: 5
print("新数组:", nums[:length]) # 输出: [1, 2, 3, 4, 5]
给定一个链表,判断链表中是否有环。
初始化两个指针,一个慢指针(每次移动一步),一个快指针(每次移动两步)。
如果链表中存在环,快指针最终会追上慢指针。
如果快指针到达链表末尾(None),则链表中没有环。
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def has_cycle(head):
if not head or not head.next:
return False
slow, fast = head, head.next # 初始化快慢指针
while fast and fast.next:
if slow == fast:
return True # 快指针追上慢指针,存在环
slow = slow.next # 慢指针移动一步
fast = fast.next.next # 快指针移动两步
return False # 快指针到达末尾,无环
# 示例
# 构造一个有环的链表
node1 = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
node4 = ListNode(4)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node2 # 形成环
print(has_cycle(node1)) # 输出: True
给定一个数组和一个滑动窗口的大小,找到每个滑动窗口中的最大值。
使用双指针维护一个滑动窗口。
左指针表示窗口的起始位置,右指针表示窗口的结束位置。
遍历数组,计算每个窗口的最大值。
from collections import deque
def max_sliding_window(nums, k):
if not nums or k == 0:
return []
result = []
window = deque() # 使用双端队列存储窗口中的索引
for right in range(len(nums)):
# 移除窗口中小于当前元素的索引
while window and nums[window[-1]] < nums[right]:
window.pop()
window.append(right) # 将当前元素索引加入窗口
# 移除窗口左侧超出范围的索引
if window[0] == right - k:
window.popleft()
# 当窗口大小达到 k 时,记录最大值
if right >= k - 1:
result.append(nums[window[0]])
return result
# 示例
nums = [1, 3, -1, -3, 5, 3, 6, 7]
k = 3
print(max_sliding_window(nums, k)) # 输出: [3, 3, 5, 5, 6, 7]
双指针算法是一种高效且灵活的算法技巧,适用于多种场景,如数组遍历、滑动窗口、链表操作等。
通过合理设计指针的初始位置、移动规则和终止条件,可以显著优化算法的时间复杂度和空间复杂度。
掌握双指针算法,能够帮助你更好地解决实际问题。
双指针算法通过两个指针的协同工作,能够高效地解决数组、链表等问题。以下是双指针算法的核心要点:
指针初始化:根据问题需求初始化指针的位置。
指针移动规则:根据条件决定指针的移动方向。
终止条件:确保算法在正确条件下终止。
通过以上示例和代码,可以更好地理解和掌握双指针算法的应用。
© 著作权归作者所有