Python編程題47--迴文鏈表

題目

給你一個單鏈表的頭節點 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編程題彙總(持續更新中……)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章