題目
給你一個單鏈表的頭節點 head ,請你判斷該鏈表是否爲迴文鏈表。如果是,返回 True ;否則,返回 False。
例如:
原鏈表轉換爲列表:[1, 2, 2, 1],返回結果:True
原鏈表轉換爲列表:[1, 2],返回結果:False
說明:
- 返回結果時,鏈表中各節點的指向需要和最開始保持一致。
已知 鏈表節點的定義、鏈表與列表相互轉換 的代碼如下:
class ListNode: # 單鏈表
def __init__(self, val=0, next=None):
self.val = val # 鏈表節點上存儲的元素
self.next = next # 指向下一個鏈表節點
def list_to_list_node(numbers): # 將列表轉換爲單向鏈表,並返回鏈表的頭節點
dummy_head = ListNode(0)
pre = dummy_head
for number in numbers:
pre.next = ListNode(number)
pre = pre.next
pre = dummy_head.next
return pre
def list_node_to_list(node): # 將單向鏈表轉換爲列表
result = []
while node:
result.append(node.val)
node = node.next
return result
實現思路1
- 將原鏈表中所有數據存儲到一個列表中,然後再判斷是否迴文
- 判斷列表是否迴文,可以定義2個指針:left、right,一個從頭開始往後移動,另一個從最後開始往前移動,每次判斷指向的元素是否相同,如果不相同那麼就說明不是迴文,直接返回 False
代碼實現1
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
cur, length = head, 0
result = []
while cur is not None: # 遍歷鏈表,把所有節點上的元素都存儲到列表 result 中
length += 1
result.append(cur.val)
cur = cur.next
left, right = 0, length - 1 # 定義2個指針,一個從頭開始往後,另一個從最後開始往前
while left < right:
if result[left] != result[right]: # 如果發現 left 和 right 對應的元素不一致,則說明不是迴文
return False
left += 1
right -= 1
return True
- 時間複雜度:O(n)
- 空間複雜度:O(n)
當然,我們在上面把鏈表元素都存儲到列表 result 後,也可以直接將列表與其反轉後的列表進行比較,代碼如下:
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
cur = head
result = []
while cur is not None: # 遍歷鏈表,把所有節點上的元素都存儲到列表 result 中
result.append(cur.val)
cur = cur.next
return result == result[::-1]
實現思路2
- 使用
雙指針
的方式來實現 - 從鏈表中找到中間節點,將鏈表分爲2部分:前半部分、後半部分,前半部分從原鏈表的頭節點到中間節點,後半部分則是從原鏈表中間節點的下一個節點到最後節點
- 反轉原鏈表的後半部分,得到反轉後的頭節點 reverse_head
- 定義一個變量,用於標記最終判斷結果,默認爲True
- 遍歷兩個鏈表,前半部分鏈表從head開始移動,反轉後半部分的鏈表從reverse_head開始移動,依次比較節點元素是否一致,如果不一致則將結果標記爲 False ,同時 break 跳出循環
- 比較結束後,因爲原鏈表被分割成了兩部分,所以需要先恢復原鏈表的指向,最後再返回最終判斷結果即可
代碼實現2
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
if head is None: # 如果是空鏈表,直接返回True
return True
middle_node = self.get_middle_node(head) # 找到中間節點
reverse_head = self.reverse_list_node(middle_node.next) # 從原鏈表中間節點的下一個節點到最後節點,進行反轉,並返回反轉後的頭節點
flag, pre, post = True, head, reverse_head
while post is not None:
# 前半部分鏈表從head開始,後半部分反轉後的鏈表從reverse_head開始,比較節點元素是否一致
if pre.val != post.val:
flag = False
break
pre = pre.next
post = post.next
middle_node.next = self.reverse_list_node(reverse_head) # 恢復原鏈表
return flag
def get_middle_node(self, head: ListNode) -> ListNode: # 找到鏈表的中間節點
slow, fast = head, head # 定義慢指針和快指針
while fast.next is not None and fast.next.next is not None:
slow = slow.next # 慢指針每次移動1位
fast = fast.next.next # 快指針每次移動2位
return slow
def reverse_list_node(self, head: ListNode) -> ListNode: # 反轉鏈表, 返回反轉後的頭節點
pre, cur = None, head
while cur is not None:
next_node = cur.next
cur.next = pre
pre = cur
cur = next_node
return pre
- 時間複雜度:O(n)
- 空間複雜度:O(1)
更多Python編程題,等你來挑戰:Python編程題彙總(持續更新中……)