跳到正文
第 234 题简单

回文链表

Palindrome Linked List

判断一条链表正着读和反着读是否完全相同。

在力扣中练习

题目描述

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

 

示例 1:

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

示例 2:

输入:head = [1,2]
输出:false

 

提示:

  • 链表中节点数目在范围[1, 105] 内
  • 0 <= Node.val <= 9

 

进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

解题思路

主解法

快慢指针 + 反转后半段

找到中点,把后半段翻过来,再从两端往中间比

单链表不能从后往前走,最直接的办法是把值复制进数组,再用双指针比较;但那需要 O(n) 额外空间。想在 O(1) 空间内完成,就把后半段原地反转。

先用快慢指针找中点:fast 每次走两步,slow 走一步。fast 到尾时 slow 在中间;奇数长度会正好停在中点。

分步图解

slow → node-1,fast → node-2。

快慢指针找中点值 · next 引用
null2#0节点 #0,值 2,next → node-19#1节点 #1,值 9,next → node-2slow4#2节点 #2,值 4,next → node-3fast7#3节点 #3,值 7,next → node-44#4节点 #4,值 4,next → node-59#5节点 #5,值 9,next → node-62#6节点 #6,值 2,next → null
1 / 3
fast 走到链尾时,slow 正好在中点;奇数长度会多出一个中心节点。

然后从中点开始反转后半段,让右半段可以从前向后读。反转时每改一条 next,都要先保存原来的后继。

分步图解

中点 node-3 已确定;从它开始把 next 反向,prev 先为 null。

反转后半段,节点位置保持不变值 · next 引用
null2#0节点 #0,值 2,next → node-19#1节点 #1,值 9,next → node-24#2节点 #2,值 4,next → node-37中点节点 中点,值 7,next → node-4cur4#4节点 #4,值 4,next → node-59#5节点 #5,值 9,next → node-62#6节点 #6,值 2,next → null
prev→ null
1 / 3
从中心开始把 next 反向,直到右半段可以从前向后读。

最后 left 从原头、right 从反转后的头同时前进,逐对比较,直到 right 走完。

分步图解

left 回到 head,right 指向反转后的尾;现在比较两端。

从两端向中间比较值 · next 引用
null2#0节点 #0,值 2,next → node-1left9#1节点 #1,值 9,next → node-24#2节点 #2,值 4,next → node-37中点节点 中点,值 7,next → null4#4节点 #4,值 4,next → node-39#5节点 #5,值 9,next → node-42#6节点 #6,值 2,next → node-5right
1 / 3
left 从原头前进,right 从反转后的头前进,逐对比较。

自拟主例是奇数长度,两个指针最后会同时停在中点;这一次比较的是同一个节点,天然相等,不需要特殊跳过。

时间 O(n)空间 O(1)

易错点

  • 快指针初始化成 head->next:偶数长度会提前停在前半段末尾,后半段少一个节点。
  • 反转循环写成 while (slow->next):会漏掉最后一个节点,右半段缺尾。
  • 比较循环用 while (left != right):奇数长度会在中点卡住,必须用 right 是否走完来控制。
  • 反转后没有恢复链表:如果调用方还要使用原链表,需要再反转一次还原。
对照解法

复制到数组 · 双指针

先把链表拍平成数组,再判断回文

最好写、也最容易调试,但需要 O(n) 额外空间,不满足原地优化的目标。

遍历链表,把每个节点的值放进 vector,问题立刻变成“数组是否回文”。数组支持随机访问,左右指针相向而行即可。

这个方案不修改链表,也不会破坏调用方的数据;代价是 O(n) 额外空间。如果题目不限制空间,或者链表之后还要复用,它反而更安全。

面试里可以先说这个方案,再补上快慢指针版本,展示对空间复杂度的取舍。

  1. 1遍历链表,把值复制到数组。
  2. 2left、right 指向数组两端。
  3. 3相向比较,遇到不等返回 false。
  4. 4全部通过返回 true。
时间 O(n)空间 O(n)

易错点

  • 只比较值不比较位置:回文必须两端对称,不是集合相同。
  • 空链表和单节点链表应直接返回 true。

代码与演示

主解法配有图解;对照解法用于比较思路、复杂度或实现方式。

演示输入head = [2,9,4,7,4,9,2]

slow、fast 从头出发;快指针每次走两步,慢指针走一步。

快慢指针找中点值 · next 引用
null2#0节点 #0,值 2,next → node-1slowfast9#1节点 #1,值 9,next → node-24#2节点 #2,值 4,next → node-37#3节点 #3,值 7,next → node-44#4节点 #4,值 4,next → node-59#5节点 #5,值 9,next → node-62#6节点 #6,值 2,next → null
1 / 8
查看 C++ 代码

延伸阅读

  • 快慢指针找中点 + 原地反转,是链表里反复出现的组合:回文、重排、折半都可以用。
  • 如果要求判断后恢复原链表,记得在比较结束后再把后半段反转回去。