466. 使用快慢指標把有序連結串列轉換二叉搜尋樹

資料結構和演算法發表於2020-10-26

想了解更多資料結構以及演算法題,可以關注微信公眾號“資料結構和演算法”,每天一題為你精彩解答。也可以掃描下面的二維碼關注
在這裡插入圖片描述

問題描述

給定一個單連結串列,其中的元素按升序排序,將其轉換為高度平衡的二叉搜尋樹


本題中,一個高度平衡二叉樹是指一個二叉樹每個節點的左右兩個子樹的高度差的絕對值不超過 1。


示例:

在這裡插入圖片描述

快慢指標解決

二叉搜尋樹的特點是當前節點大於左子樹的所有節點,並且小於右子樹的所有節點,並且每個節點都具有這個特性。


題中說了,是按照升序排列的單連結串列,我們只需要找到連結串列的中間節點,讓他成為樹的根節點,中間節點前面的就是根節點左子樹的所有節點,中間節點後面的就是根節點右子樹的所有節點,然後使用遞迴的方式再分別對左右子樹進行相同的操作……

這裡就以連結串列1→2→3→4→5為例來畫個圖看一下
在這裡插入圖片描述

我們看到上面連結串列的中間節點3就是二叉搜尋樹的根節點,然後再對左右子節點以同樣的方式進行操作……,最後再來看下程式碼

public TreeNode sortedListToBST(ListNode head) {
    //邊界條件的判斷
    if (head == null)
        return null;
    if (head.next == null)
        return new TreeNode(head.val);
    //這裡通過快慢指標找到連結串列的中間結點slow,pre就是中間
    //結點slow的前一個結點
    ListNode slow = head, fast = head, pre = null;
    while (fast != null && fast.next != null) {
        pre = slow;
        slow = slow.next;
        fast = fast.next.next;
    }
    //連結串列斷開為兩部分,一部分是node的左子節點,一部分是node
    //的右子節點
    pre.next = null;
    //node就是當前節點
    TreeNode node = new TreeNode(slow.val);
    //從head節點到pre節點是node左子樹的節點
    node.left = sortedListToBST(head);
    //從slow.next到連結串列的末尾是node的右子樹的結點
    node.right = sortedListToBST(slow.next);
    return node;
}

通過集合list解決

實際上還可以把連結串列中的值全都儲存到集合list中,每次把list分為兩部分,和上面原理一樣

public TreeNode sortedListToBST(ListNode head) {
    List<Integer> list = new ArrayList<>();
    //把連結串列節點值全部提取到list中
    while (head != null) {
        list.add(head.val);
        head = head.next;
    }
    return sortedListToBSTHelper(list, 0, list.size() - 1);

}

TreeNode sortedListToBSTHelper(List<Integer> list, int left, int right) {
    if (left > right)
        return null;
    //把list中資料分為兩部分
    int mid = left + (right - left) / 2;
    TreeNode root = new TreeNode(list.get(mid));
    root.left = sortedListToBSTHelper(list, left, mid - 1);
    root.right = sortedListToBSTHelper(list, mid + 1, right);
    return root;
}

總結

做這道題我們首先要明白什麼是二叉搜尋樹,這題是讓把升序的連結串列轉化為二叉搜尋樹,如果是把升序的陣列轉化為二叉搜尋樹可能就更容易些了,但不管是什麼資料結構,最終實現原理還是一樣的。


在這裡插入圖片描述

相關文章