问题描述
Given a singly linked list, determine if it is a palindrome.
Follow up:
Could you do it in O(n) time and O(1) space?
给定一个单链表,判断它是否是回文。
跟进:
你能在O(n)时间和O(1)空间内实现吗?
输入: 1->2
输出: false
输入: 1->2->2->1
输出: true
Python 实现
实现一:将链表转换成列表(list),利用 Python 列表的特性,判断倒序的列表与原列表是否相等,从而判断链表是否为回文链表。此时,新建的 list 及其倒序的切片占用新的内存空间。
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
l = []
while head != None:
l.append(head.val)
head = head.next
if l == l[::-1]:
return True
else:
return False
实现二:利用栈后进先出(LIFO)的特性。先遍历一次链表,把所有节点数值添加到栈中,再利用栈后入先出的特性,与原链表的节点数值比较,从而判断是否为回文链表。这种实现需要遍历两次链表,同时还要开拓新的内存空间储存栈。
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
stack = []
tmp = head
while tmp != None:
stack.append(tmp.val)
tmp = tmp.next
cur = head
while cur != None:
if stack[-1] == cur.val:
stack.pop()
cur = cur.next
else:
return False
return True
实现三:递归法。首先需要定义一个全局的变量 cur 来记录以比较的结点位置,对头结点调用递归函数,比较当前结点数值与 cur 指向的节点数值,相等则 cur 指向下一个值,结束当前函数调用,比较对象又返回到前一个结点,依次比较下去从而判断链表是否为回文链表。
从原理上,这是一个可行的实现思路。但是,递归调用的缺点仍然不能被避免,当链表长度过大时,多次递归调用容易导致栈溢出,运行时间过长。因此这并不是一个理想的选择。
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
self.cur = head
return self.compare(head)
def compare(self, node):
if node == None:
return True
b = self.compare(node.next) and node.val == self.cur.val
self.cur = self.cur.next
return b
实现四:上述三种实现方法基本都是多次遍历了整个链表,在这过程中重复比较了一些结点。但判断回文链表只需要判断前半个链表和后半个链表对应值相等即可,所以我们可以尝试去找到链表的中点,这个过程可以用快慢指针的方法来实现。快指针走两步,慢指针走一步,慢指针同时把每次读到的数值存到一个栈中,当快指针遍历到链表末尾时,慢指针刚好遍历到链表中点。此时只需要将慢指针接下来读取到的数值,与栈的值进行比较即可。
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if head == None or head.next == None:
return True
slow, fast = head, head
stack = [slow.val]
while fast.next != None and fast.next.next != None:
slow = slow.next
fast = fast.next.next
stack.append(slow.val)
if fast.next == None:
stack.pop() # Skip the middle val if the length of linked list is odd.
while slow.next != None:
slow = slow.next
if slow.val == stack[-1]:
stack.pop()
else:
return False
return True
实现五:如果要实现 O(1) 的空间复杂度,那就不能使用 stack 相关的方法了,要替代 stack 后进先出的特性,我们可以在找到链表中点位置之后,将后半部分的链表翻转一下,就可以按照回文顺序进行比较了。这样子就是 in-place 的实现。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if head == None or head.next == None:
return True
slow, fast = head, head
while fast.next != None and fast.next.next != None:
slow = slow. next
fast = fast.next.next
# Reverse the latter half linked list.
last = slow.next
while last.next != None:
tmp = last.next
last.next = tmp.next
tmp.next = slow.next
slow.next = tmp
pre = head
while slow.next != None:
slow = slow.next
if pre.val != slow.val:
return False
pre = pre.next
return True

本文探讨了多种判断链表是否为回文的有效方法,包括列表转换、栈利用、递归及快慢指针技巧,特别关注O(n)时间与O(1)空间的解决方案。
1963

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



