234. 回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true;否则,返回 false 。
示例 1:
输入:head = [1,2,2,1]
输出:true

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

算法思路
通过 快慢指针分割链表 + 反转后半链表 的方法判断链表是否为回文。核心思想是将链表分为前后两半,反转后半部分后与前半部分逐一比较,最后恢复链表结构。具体步骤如下:
- 分割链表: 使用快慢指针找到前半部分的尾节点,将链表分为前后两段。
- 反转后半链表: 将后半部分链表反转,便于顺序比较。
- 比较节点值: 同时遍历前半部分和后半部分,逐一比较节点值是否相等。
- 恢复链表(可选):将后半部分再次反转还原,恢复链表原始结构。
步骤详解
- 快慢指针分割链表:
- 快指针每次移动两步,慢指针每次移动一步。
- 当快指针到达链表末尾时,慢指针恰好指向前半部分的尾节点。
- 示例:链表
1->2->2->1,慢指针停在第二个节点2,分割为前1->2和后2->1。
- 反转后半部分链表:
- 通过迭代法反转后半部分链表。例如,
2->1反转为1->2。
- 通过迭代法反转后半部分链表。例如,
- 比较节点值:
- 从头部和反转后的后半部分头部开始遍历,比较每个节点的值。
- 示例:比较
1->2和1->2,发现所有节点值相等,返回 True。
- 恢复链表结构:
- 再次反转后半部分链表并拼接回前半部分,保持链表原始结构。
关键点
- 快慢指针的正确性: 确保分割点准确,无论链表长度为奇数或偶数。
- 反转链表的实现: 通过迭代法正确反转后半部分链表。
- 比较逻辑: 仅需比较前半部分和反转后的后半部分,忽略中间节点(奇数长度时)。
- 空间优化: 全程仅使用指针变量,空间复杂度为 O(1)。
复杂度分析
时间复杂度:O(n)O(n)O(n)
分割链表:O(n/2)O(n/2)O(n/2)
反转链表:O(n/2)O(n/2)O(n/2)
比较节点值:O(n/2)O(n/2)O(n/2)
恢复链表:O(n/2)O(n/2)O(n/2)
总体时间复杂度为线性 O(n)O(n)O(n)。
空间复杂度:O(1)O(1)O(1)
仅使用常数级别的额外空间(指针变量)。
算法代码
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
if head is None:
return True
# 找到前半部分链表的尾节点并反转后半部分链表
first_half_end = self.end_of_first_half(head)
second_half_start = self.reverse_list(first_half_end.next)
# 判断是否回文
result = True
first_position = head
second_position = second_half_start
while result and second_position is not None:
if first_position.val != second_position.val:
result = False
first_position = first_position.next
second_position = second_position.next
# 还原链表并返回结果
first_half_end.next = self.reverse_list(second_half_start)
return result
def end_of_first_half(self, head):
fast = head
slow = head
while fast.next and fast.next.next:
fast = fast.next.next
slow = slow.next
return slow
def reverse_list(self, head):
previous = None
current = head
while current is not None:
next_node = current.next
current.next = previous
previous = current
current = next_node
return previous

1042

被折叠的 条评论
为什么被折叠?



