链表高频面试题有哪些?

2025年 阅读约 15 分钟 面试指南 · 算法

深入解析链表高频面试题:反转链表(迭代+递归)、环形链表检测(快慢指针+入环点)、合并有序链表、删除倒数第N个节点、LRU缓存,附面试模拟问答。

一句话总结

链表高频题核心技巧:1)哑节点(dummy)简化头节点处理;2)快慢指针解决环检测、找中点、倒数第 K 个;3)多指针(prev/curr/next)解决反转、交换;4)递归优雅解决反转、合并。时间复杂度通常 O(n),空间 O(1)(迭代)或 O(n)(递归栈)。

初级理解

反转链表(LeetCode 206)

# 迭代法(三指针) def reverse_list(head): prev = None curr = head while curr: next_temp = curr.next # 保存下一个 curr.next = prev # 反转 prev = curr # 移动 prev curr = next_temp # 移动 curr return prev # 递归法 def reverse_list_recursive(head): if not head or not head.next: return head new_head = reverse_list_recursive(head.next) head.next.next = head # 反转 head.next = None return new_head

合并两个有序链表(LeetCode 21)

def merge_two_lists(l1, l2): dummy = ListNode(0) # 哑节点 curr = dummy while l1 and l2: if l1.val <= l2.val: curr.next = l1 l1 = l1.next else: curr.next = l2 l2 = l2.next curr = curr.next curr.next = l1 or l2 # 剩余部分 return dummy.next
一句话总结:反转用三指针(prev/curr/next),合并用哑节点简化边界。

中级深入

环形链表检测(LeetCode 141 + 142)

# 判断是否有环(快慢指针) def has_cycle(head): slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: return True return False # 找到入环点 def detect_cycle(head): slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: # 相遇 # 从头和相遇点同时走,再次相遇就是入环点 ptr = head while ptr != slow: ptr = ptr.next slow = slow.next return ptr return None # 原理: # 设头到入环点距离 a,入环点到相遇点距离 b,相遇点到入环点距离 c # 慢指针走 a+b,快指针走 a+b+n(b+c) # 快指针速度是慢指针 2 倍:2(a+b) = a+b+n(b+c) # → a = (n-1)(b+c) + c # → 从头走 a 步 = 从相遇点走 c + n-1 圈 → 在入环点相遇

删除倒数第 N 个节点(LeetCode 19)

def remove_nth_from_end(head, n): dummy = ListNode(0, head) fast = slow = dummy # fast 先走 n+1 步 for _ in range(n + 1): fast = fast.next # fast 和 slow 同时走 while fast: fast = fast.next slow = slow.next # slow 指向倒数第 n+1 个节点 slow.next = slow.next.next return dummy.next
中级要点:快慢指针解决环检测和倒数第 K 个;哑节点简化删除头节点的边界。

高级拓展

K 个一组反转链表(LeetCode 25)

def reverse_k_group(head, k): # 检查是否有 k 个节点 curr = head count = 0 while curr and count < k: curr = curr.next count += 1 if count < k: return head # 反转前 k 个 prev = None curr = head for _ in range(k): next_temp = curr.next curr.next = prev prev = curr curr = next_temp # head 变成尾节点,连接下一组 head.next = reverse_k_group(curr, k) return prev # prev 是新的头节点

链表排序(LeetCode 148)— 归并排序

def sort_list(head): if not head or not head.next: return head # 快慢指针找中点 slow, fast = head, head.next while fast and fast.next: slow = slow.next fast = fast.next.next mid = slow.next slow.next = None # 断开 left = sort_list(head) right = sort_list(mid) return merge_two_lists(left, right)

实战场景

场景:LRU 缓存(LeetCode 146)

class LRUCache: def __init__(self, capacity): self.cap = capacity self.cache = {} # key → Node # 双向链表:head ↔ ... ↔ tail self.head = Node(0, 0) # 哨兵头 self.tail = Node(0, 0) # 哨兵尾 self.head.next = self.tail self.tail.prev = self.head def get(self, key): if key not in self.cache: return -1 node = self.cache[key] self._move_to_head(node) # 移到头部 return node.val def put(self, key, value): if key in self.cache: node = self.cache[key] node.val = value self._move_to_head(node) else: node = Node(key, value) self.cache[key] = node self._add_to_head(node) if len(self.cache) > self.cap: removed = self._remove_tail() del self.cache[removed.key]

面试模拟

面试官:怎么判断链表有环?找到入环点?

你:快慢指针,快指针每次走两步,慢指针每次走一步。如果相遇则有环。找入环点:相遇后,一个指针从头开始,一个从相遇点开始,同时每次走一步,再次相遇就是入环点。原理是数学推导:a = (n-1)(b+c) + c。

面试官:反转链表的递归思路?

你:递归到最后一个节点作为新头返回。回溯时,head.next.next = head 让下一个节点指向当前节点,head.next = None 断开原来的指向。关键是理解递归的"递"和"归":递到最深处,归时逐层反转。