文章目录
- 一、题目理解
- 二、问题分析
- 三、解法一:数组辅助法(最易理解)
- [四、解法二:快慢指针 + 反转链表(空间优化)](#四、解法二:快慢指针 + 反转链表(空间优化))
- 五、总结
一、题目理解
题目链接: Palindrome Linked List
题目描述:
给定一个单链表的头节点 head,判断该链表是否为回文链表。
如果链表从前往后与从后往前的节点值序列相同,则认为是回文。
示例:
输入:head = [1,2,2,1]
输出:true
输入:head = [1,2]
输出:false
二、问题分析
我们要判断链表的节点值序列是否是回文结构。
具体而言,若链表的值为 1 -> 2 -> 3 -> 2 -> 1,从前往后与反向的值序列一致,此时返回 true。
链表无法直接随机访问,因此不能像数组那样轻易反转或双指针比较,需要借助额外手段。
三、解法一:数组辅助法(最易理解)
核心思路
将链表中的节点值依次存入数组,然后利用数组的下标进行首尾双指针对比。
步骤解析(流程图)
否
是
否
是
开始
创建空数组 list
遍历链表,将节点值存入 list
设置左右指针 left=0, right=list.size()-1
list[left] == list[right]?
返回 false
left++, right--
left >= right?
返回 true
时间与空间复杂度
- 时间复杂度: O(n)
遍历链表一次存入数组,再遍历一半数组比较。 - 空间复杂度: O(n)
需要一个额外的数组存储节点值。
Java代码实现
java
class ListNode {
int val;
ListNode next;
ListNode(int val) { this.val = val; }
}
public class Solution {
public boolean isPalindrome(ListNode head) {
List<Integer> list = new ArrayList<>();
ListNode node = head;
while (node != null) {
list.add(node.val);
node = node.next;
}
int left = 0, right = list.size() - 1;
while (left < right) {
if (!list.get(left).equals(list.get(right))) {
return false;
}
left++;
right--;
}
return true;
}
}
四、解法二:快慢指针 + 反转链表(空间优化)
核心思路
- 使用快慢指针 找到链表的中点。
- 快指针每次走两步,慢指针每次走一步,当快指针到达末尾时,慢指针就在中间位置。
- 将后半部分链表反转。
- 从链表头开始与反转后的后半部分进行逐节点比较。
- 若全部相同则为回文。
关键步骤图示
找中点
slow
fast
1
2
3
2
1
反转后半部分:
1
2
3
2
1
对比:
反转后半部分 前半部分 反转后半部分 前半部分 若有不同则非回文 比较节点值是否相等 向下一个节点移动
时间与空间复杂度
- 时间复杂度: O(n)
找中点 O(n/2),反转 O(n/2),比较 O(n/2)。 - 空间复杂度: O(1)
只使用常量指针变量。
Java代码实现
java
public class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) return true;
// 1. 快慢指针找到中点
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 2. 反转后半部分链表
ListNode secondHalf = reverseList(slow);
// 3. 从头与反转后的后半比较
ListNode firstHalf = head;
while (secondHalf != null) {
if (firstHalf.val != secondHalf.val) {
return false;
}
firstHalf = firstHalf.next;
secondHalf = secondHalf.next;
}
return true;
}
private ListNode reverseList(ListNode head) {
ListNode prev = null, curr = head;
while (curr != null) {
ListNode nextNode = curr.next;
curr.next = prev;
prev = curr;
curr = nextNode;
}
return prev;
}
}
五、总结
| 解法 | 核心思路 | 时间复杂度 | 空间复杂度 | 特点 |
|---|---|---|---|---|
| 数组辅助法 | 用数组保存节点值再比较 | O(n) | O(n) | 简单易理解 |
| 快慢指针+反转法 | 找中点后反转后半部分比较 | O(n) | O(1) | 高效且空间最优 |