时间复杂度O(N) 额外空间复杂度O(1)的解
N:链表长度(问题的规模)
通过快慢指针找到中点节点 遍历N
反转中点右边节点的指向 遍历0.5N
判断是否回文 遍历0.5N
恢复中点右边的节点的指向 0.5N
总的需要遍历链表2.5N次
def isPalindrome(head):
if not head or not head.next:
return True
# 快慢指针
slow = fast = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
leftHead = head
rightHead = None
cur = slow
while cur:
pre = cur
cur = cur.next
pre.next = rightHead
rightHead = pre
# 保存右边的头节点
cur = rightHead
while leftHead:
if leftHead.val != rightHead.val:
return False
leftHead = leftHead.next
rightHead = rightHead.next
# 恢复链表
post = None
while cur:
pre = cur
cur = cur.next
pre.next = post
post = pre
return True
优化
通过快慢指针找中点的时候,反转中点左边的节点的指向,判断是否回文的时候就反转中点左边节点的指向。这种方式需要判断链表长度的奇偶性。
优化后需要遍历1.5N
def isPalindrome1(head):
if not head or not head.next:
return True
if not head.next.next:
if head.val != head.next.val:
return False
else:
return True
odd = True
slow = head
leftHead = None
fast = head.next
while fast.next and fast.next.next:
preslow = slow
slow = slow.next
preslow.next = leftHead
leftHead = preslow
fast = fast.next.next
if not fast.next:
odd = False
slowNext = rightHead = slow.next
if odd:
rightHead = slow.next.next
slow.next = leftHead
leftHead = slow
while leftHead:
if leftHead.val != rightHead.val:
return False
# 恢复链表指向
preslow = leftHead
leftHead = leftHead.next
preslow.next = slowNext
slowNext = preslow
rightHead = rightHead.next
return True
对数器(验证)
def varifyIsPalindrome(head):
if not head or not head.next:
return True
lst = []
cur = head
while cur:
lst.append(cur.val)
cur = cur.next
for i in range(len(lst)//2):
if lst[i] != lst[len(lst)-1-i]:
return False
return True
测试
def test(num=10000):
for i in range(num):
head = generateLinkedList(20)
res2 = varifyIsPalindrome(head)
res1 = isPalindrome2(head)
if res1 is not res2:
print("varifyIsPalindrome Failed")
traverseLinkedList(head)
print()
print("isPalindrome", res1)
print("varifyIsPalindrome", res2)
break
else:
print("nice!")
if __name__ == '__main__':
test()