题目要求
判断一个链表是否为回文链表。
解题思路
不限制时间复杂度的情况下是非常简单的题目,可以有多种方法完成本题。
如果限制了 O ( n ) O(n) O(n) 时间复杂度且 O ( 1 ) O(1) O(1) 空间复杂度那么可以按照以下思路。
链表题中看到 O ( n ) O(n) O(n) 时间复杂度且 O ( 1 ) O(1) O(1) 空间复杂度可以考虑快慢指针就相当于数组题看到 O ( n ) O(n) O(n) 时间复杂度且 O ( 1 ) O(1) O(1) 空间复杂度可以考虑双指针一样。
那么从快慢指针开始思考。我们知道,快慢指针可以找链表的中点。回文链表只需要对链表中点两边进行比较就可以知道结果,因此先用快慢指针找到链表的中点。
找到中点以后需要令前半部分末尾等于 N o n e None None,因此为了方便起见,前半部分找到中点左边的一个点,就停止。假设中间节点是 m e d i a n median median,我们希望 s l o w slow slow 停留在 m e d i a n median median 的左边第一个节点,这样我们只要令 s l o w . n e x t = N o n e slow.next = None slow.next=None 就可以得到左半部分链表。
此时右半部分链表只需要令 c u r = s l o w . n e x t cur = slow.next cur=slow.next,这样 c u r cur cur 就是右半链表。
利用双指针反转链表的方式,反转链表之后进行比较节点的值就可以得到结果。在比较的时候,我们之前这样处理以后,右半部分一定不大于左半部分的长度,因此遍历右半部分,这样如果链表长度是奇数的时候,不需要考虑中间节点。
以下用多张图具体说明这个过程:
- 链表长度是奇数
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
- 链表长度是偶数时,可以尝试用同样的方式处理
代码
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
if not head:
return True
fast = slow = head
while fast.next and fast.next.next:
fast = fast.next.next
slow = slow.next
pre = None
cur = slow.next
slow.next = None
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
while pre:
if head.val != pre.val:
return False
head = head.next
pre = pre.next
return True
复杂度分析
时间复杂度
O
(
n
)
O(n)
O(n) 其中
n
n
n 是链表的长度
空间复杂度
O
(
1
)
O(1)
O(1) 没有使用额外空间