判断回文链表:从暴力到最优的算法进阶
本文带你掌握判断回文链表的三种方法,重点解析最优解的“快慢指针+链表反转”技巧,助你轻松应对算法面试。
核心知识点:回文链表的判断策略
回文链表的判断需解决“单向链表无法逆序访问”的问题,常见方法有三种:
- 暴力法:将链表转为数组,直接比较正序与逆序。
- 递归法:利用递归栈逆序访问节点,但空间复杂度为 O(n)。
- 最优解:结合“快慢指针找中点”和“反转后半部分链表”,空间复杂度降为 O(1)。
题目解析:LeetCode 234. 回文链表
题目描述
给定单链表的头节点 head,判断链表是否为回文链表(正读与反读一致)。
示例
- 输入:
head = [1,2,2,1]→ 输出:true - 输入:
head = [1,2]→ 输出:false
方法一:暴力法(数组辅助)
将链表节点值存入数组,直接比较正序与逆序。
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
vals = []
cur = head
while cur:
vals.append(cur.val)
cur = cur.next
return vals == vals[::-1] # 数组正序与逆序比较
复杂度分析:时间 O(n),空间 O(n)。
方法二:最优解(快慢指针+反转链表)
步骤:
- 找中点:快指针走两步,慢指针走一步,慢指针最终指向中点。
- 反转后半部分:从慢指针位置反转链表后半部分。
- 双指针比较:头指针与反转后的尾指针同步移动,比较节点值。
- 恢复链表:可选,将后半部分链表恢复原状(面试加分项)。
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
# 1. 找中点:快慢指针
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 2. 反转后半部分链表
def reverseList(node):
pre = None
cur = node
while cur:
temp = cur.next
cur.next = pre
pre = cur
cur = temp
return pre
# 3. 比较前后两部分
left = head
right = reverseList(slow)
while right: # right 长度可能比 left 短(奇数节点时)
if left.val != right.val:
return False
left = left.next
right = right.next
return True
复杂度分析:时间 O(n),空间 O(1)。
总结
- 暴力法:简单但空间复杂度高,适合快速实现。
- 最优解:结合快慢指针与链表反转,是面试中的标准答案,需熟练掌握。