天天看點

排序清單轉換為二分查找樹

題目描述:給出一個所有元素以升序排序的單連結清單,将它轉換成一棵高度平衡的二分查找樹

我們之前做過一道将排序數組轉換為二分查找樹的問題,詳見:點選打開連結

将連結清單轉換為二分查找樹與上面這道題的基本思想一模一樣(在這裡,高度平衡,也就是高度最小),是以我們要解決的問題就是查找到排序連結清單的中值,作為根節點,然後将連結清單分割,分别按照同樣的思想生成左右子樹。(如果對這個算法有疑問,請先搞懂我剛才給出的連結的那道題)

那麼如何查找連結清單的中值呢?當然不能全周遊一遍,再回溯。這方法效率太低,我在這裡給出一種通用的“快慢指針法”

我假設看我這篇文章的人對連結清單的基本結構已經很熟悉了。那麼現在可以設定兩個指針slow和fast,我們令這兩個指針一開始都指向連結清單的頭結點--head,然後slow每次指向連結清單的下一位(就是它現在所指向的節點的next),而fast每次指向他的下一位的下一位(也就是每次向後移動兩個節點),那當fast指向尾節點的時候,slow指向的剛好是中間節點。

舉個例子:1->2->3->4->5

1. 一開始,slow,fast都指向1

2. slow移動一位,指2;fast移動兩位,指3

3. slow接着移動一位,指3;fast接着移動兩位,指5. 此時fast指向尾節點,slow剛好指向中間節點。

這是快慢指針的基本應用,當然具體處理問題的時候,快慢指針會根據具體問題做相應修改,是以,一定要靈活運用。

就拿這道題來說吧,按照上面的快慢指針法,當然能找到中間節點,但是,随後我們是要對連結清單分割的,而隻有知道中間節點之前的那個節點,才能實作“摘鍊”(就是把連結清單的一部分“摘”下來,形成單獨的連結清單)

是以,此處也有個通用的技巧,就是在連結清單的頭結點之前人為的放置一個dummy節點幫助我們處理問題。還是上面的那個例子,當放置了dummy節點之後,就變成下面這個樣子了:

dummy->1->2->3->4->5

可以令slow初始時指向dummy,fast初始時指向head,還是剛才那樣掃描連結清單,發現當fast指向尾節點時,slow剛好指向2,正好在中間節點前面。我們就能實作摘鍊了。

是以,這個題的思路沒什麼值得注意的,倒是對連結清單的操作,是需要學習的。

代碼可以給出了:

"""
Definition of ListNode
class ListNode(object):

    def __init__(self, val, next=None):
        self.val = val
        self.next = next

Definition of TreeNode:
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None
"""
class Solution:
    """
    @param head: The first node of linked list.
    @return: a tree node
    """
    def sortedListToBST(self, head):
        if head is None:
            return None
        # 随意指派給dummy即可
        dummy = TreeNode(-1)
        # dummy連在head前面
        dummy.next = head
        slow, fast = dummy, head
        # 直到fast指向尾巴
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        # 找到中間節點了,為slow.next
        root = TreeNode(slow.next.val)
        # 以下三行為摘鍊,需注意操作順序
        second = slow.next.next
        slow.next = None
        first = dummy.next
        # 遞歸
        root.left = self.sortedListToBST(first)
        root.right = self.sortedListToBST(second)
        return root
        # write your code here
           

連結清單對于算法設計的意義是什麼呢?我個人的了解:連結清單是樹和圖的基礎,也可以說是一種結構簡單的樹或者圖,而樹和圖能夠形象的刻畫現實問題,這為算法的設計提供了廣闊的空間。

繼續閱讀