问题描述:
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
示例1:

**输入:**head = [1,2,2,1]
**输出:**true
示例2:

**输入:**head = [1,2]
**输出:**false
解决方法:
方法一:数组+双指针
算法思路:
-
遍历链表,将节点值复制到数组中;
-
使用双指针法判断数组是否为回文。
代码实现:
python
def isPalindrome(head):
values = []
curr = head
while curr:
values.append(curr.val)
curr = curr.next
left, right = 0, len(values) - 1
while left < right:
if values[left] != values[right]:
return False
left += 1
right -= 1
return True
复杂度分析:
- 时间复杂度:O(n),需要遍历链表和数组各一次
- 空间复杂度:O(n),需要额外的数组空间存储节点值
方法二:快慢指针+翻转
算法思路:
-
使用快慢指针找到链表中点;
-
反转后半部分链表;
-
比较前半部分和反转后的后半部分。
代码实现:
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
# 快慢指针
if not head or not head.next:
return True
fast = low = head
# 查找反转的起点
while fast and fast.next:
low = low.next
fast = fast.next.next
# 反转后半部分链表
prev = None
cur = low
while cur: # 迭代反转
nxt = cur.next
cur.next = prev
prev = cur
cur = nxt
# 链表比较
left = head
right = prev
while right:
if left.val != right.val:
return False
left = left.next
right = right.next
return True
复杂度分析:
- 时间复杂度:O(n),遍历链表的次数是常数倍
- 空间复杂度:O(1),只使用了几个指针变量
问题详解:

以链表 [ 1,2,3,2,1]为例说明方法二:
1、快慢指针找中点:
- 慢指针每次走1步,快指针每次走2步;
- 最终慢指针会停在节点3上。
2、反转后半部分:
- 将 [3,2,1]反转为[1,2,3];
- 此时链表的结构被修改,但比较阶段不需要完整的结构。
3、比较前后部分:
- 前半部分: [1,2,3];
- 后半部分(反转后):[1,2,3];
- 逐个比较对应节点值。
关键点说明
- 为什么在比较部分要使用 ++while right:++后半部分长度总是整体的一部分,小于等于前半部分长度,确保只比较必要的节点对数;
- 链表的结构改变:方法二会改变链表的结构,但是比较完成后通常不需要恢复;
- 边界情况处理:空链表和单节点链表直接返回 true。
总结:
| 方法 | 优点 | 缺点 | 适用情况 |
| 数组+双指针 | 思路简单,不易出错 | 需要额外O(n)空间 | 对空间要求不高的场景 |
| 快慢指针+翻转 | 空间复杂度O(1) | 会修改原链表结构 | 对空间有严格要求的场景 |
|---|
通常情况下期望掌握第二种方法,因为它展示了更多的链表操作技巧。