AI刷题中的链表
在AI刷题中,有许多链双指针的题,这篇文章结合题目来讲一下双指针的知识点和python中的应用。
一、双指针概念
双指针是一种非常高效的算法思想,常用于数组或链表等线性结构中,通过两个指针在数据结构上以某种策略移动,从而减少时间复杂度。
双指针分为以下几种常见类型:
- 快慢指针:用于检测链表中的环、寻找中间节点等。
- 对撞指针:用于解决排序数组中的两数之和、回文检测等问题。
- 滑动窗口:用于解决子数组、子字符串相关的问题(如最长子序列、最小覆盖子串等)。
1.快慢指针示例
问题:链表环检测
给定一个链表,判断链表中是否存在环。
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def hasCycle(head):
slow = fast = head
while fast and fast.next:
# 快指针可以继续走两步
slow = slow.next # 慢指针走一步
fast = fast.next.next # 快指针走两步
if slow == fast: # 快慢指针相遇,存在环
return True
return False
在这段代码中,时间和空间复杂度分别为:
- 时间复杂度:O(n),每个节点最多被访问两次。
- 空间复杂度:O(1),只使用两个指针。
2. 对撞指针示例
问题:排序数组中的两数之和
在一个升序数组中找到两个数,使得它们的和为目标值。
def twoSum(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 []
在这段代码中,时间和空间复杂度分别为:
-
时间复杂度:O(n),左右指针各遍历一次。
-
空间复杂度:O(1)。
3.滑动窗口示例**
问题:找到字符串中的最长无重复子串
给定一个字符串,找到最长的无重复字符子串的长度。
代码实现:
def lengthOfLongestSubstring(s):
char_set = set()
left = 0
max_length = 0
for right in range(len(s)):
while s[right] in char_set: # 如果遇到重复字符,缩小窗口
char_set.remove(s[left])
left += 1
char_set.add(s[right]) # 加入新字符
max_length = max(max_length, right - left + 1) # 更新最大长度
return max_length
滑动窗口是一种动态调整范围的双指针方法,窗口右边界扩展时记录结果,左边界缩小时删除无效元素。
-
时间复杂度:O(n),每个字符最多被访问两次。
-
空间复杂度:O(min(n, m)),
m是字符集大小。
二、双指针的通用思路
-
初始化指针:确定两个指针的初始位置,通常是
left = 0和right = n-1。 -
移动条件:根据问题特点,决定如何移动指针,例如:
- 比较两数和,移动靠近目标的指针。
- 碰到重复元素时,缩小窗口。
-
边界条件:防止指针越界或进入死循环。
三、总结
- 双指针的核心在于减少不必要的遍历,提升效率。
- 根据问题特点选择适合的双指针策略(快慢、对撞、滑动窗口)。
- 配合排序或哈希表等其他技术,可以解决更复杂的问题。