1. 程式人生 > 其它 >程式設計師面試金典 - 面試題 02.06. 迴文連結串列

程式設計師面試金典 - 面試題 02.06. 迴文連結串列

技術標籤:Leetcode連結串列leetcode資料結構演算法

題目難度: 簡單

原題連結

今天繼續更新程式設計師面試金典系列, 大家在公眾號 演算法精選 裡回覆 面試金典 就能看到該系列當前連載的所有文章了, 記得關注哦~

題目描述

編寫一個函式,檢查輸入的連結串列是否是迴文的。

示例 1:

  • 輸入: 1->2
  • 輸出: false

示例 2:

  • 輸入: 1->2->2->1
  • 輸出: true

題目思考

  1. 你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題?

解決方案

思路

  • 相比傳統的陣列或者字串求迴文, 連結串列不能直接取下標, 也無法像雙向連結串列那樣用雙指標往中間靠攏比較的方法, 如何做到 O(n) 時間複雜度和 O(1) 空間複雜度呢?
  • 分析雙指標往中間靠攏比較的原理, 它是第一個和最後一個比較, 第二個和倒數第二個比較, 以此類推…
  • 所以我們可以人為將連結串列分成左右兩半部分, 然後將右半部分進行反轉, 再用雙指標從兩部分的頭節點依次往後比較即可
  • 這樣就把問題分解成了 3 個經典的小問題, 它們都可以利用雙指標來解決, 大家可以結合下面的程式碼和註釋進行理解
  • 如果題目要求恢復原來連結串列結構的話, 還可以將連結串列翻轉部分提取出來, 然後比較完之後再將右半部分轉回去, 下面程式碼也實現了這一步

複雜度

  • 時間複雜度 O(N): 只需要遍歷每個節點三遍(劃分/翻轉/比較)
  • 空間複雜度 O(1): 只使用了幾個常數空間的變數

程式碼

class
Solution: def isPalindrome(self, head: ListNode) -> bool: # 把右半部分翻轉後再雙指標依次比較, 最後將輸入連結串列結構恢復成原樣 # 第一步: 使用快慢指標找中點 fast = head slow = head while fast: fast = fast.next if fast: fast = fast.next slow = slow.
next # 此時slow就是右半部分的頭節點(左半部分長度可能相等或多1, 對應總長度是偶數和奇數的情況) # 第二步: 定義翻轉函式, 將右半部分進行翻轉 def reverse(cur): # 翻轉並返回新的頭 pre = None while cur: nex = cur.next cur.next = pre pre, cur = cur, nex return pre # 第三步: 雙指標依次比較左右兩部分對應節點, 並記錄右半部分末尾節點用於恢復原始結構 left, right = head, reverse(slow) rightTail = right res = True while left and right: if left.val != right.val: res = False break left = left.next rightTail = right right = right.next # 得到右半部分末尾節點並翻轉恢復(注意它可能不存在, 如果當原始連結串列長度小於等於1時) while rightTail and rightTail.next: rightTail = rightTail.next reverse(rightTail) return res

大家可以在下面這些地方找到我~