1. 程式人生 > 實用技巧 >劍指 Offer 07. 重建二叉樹重建二叉樹

劍指 Offer 07. 重建二叉樹重建二叉樹

  • 題目描述

輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。

例如,給出

前序遍歷 preorder =[3,9,20,15,7]
中序遍歷 inorder = [9,3,15,20,7]
返回如下的二叉樹:

3
/ \
9 20
/ \
15 7

限制:

0 <= 節點個數 <= 5000

  • 分析

首先我們需要了解下二叉樹的前序遍歷和中序遍歷的特點

前序遍歷:節點按照[ 根節點 | 左子樹 | 右子樹 ]排序,以題目示例為例:[ 3 | 9 | 20 15 7 ]

中序遍歷:節點按照[ 左子樹 | 根節點 | 右子樹 ]

排序,以題目示例為例:[ 9 | 3 | 15 20 7 ]

那麼可以得到:

前序遍歷的第一個元素即為root節點

可根據這個root找到中序遍歷中左子樹和右子樹的:[ 左子樹 | 根節點 | 右子樹 ]

根據中序遍歷的左右子樹的節點數量,可將前序遍歷劃分為[ 根節點 | 左子樹 | 右子樹 ]

根據子樹特點,我們可以通過同樣的方法對左(右)子樹進行劃分,每輪可確認三個節點的關係。此遞推性質讓我們聯想到用遞迴方法處理。

參照題解:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/mian-shi-ti-07-zhong-jian-er-cha-shu-di-gui-fa-qin/

此時需要理解的是:

            preorder_left:前序遍歷的起始座標
            preorder_right:前序遍歷的終止座標
            inorder_left:中序遍歷的起始座標
            inorder_right:中序遍歷的終止座標
此時遞迴的左子樹
class Solution:
    '''
    雜湊表+遞迴
    '''
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        rootCan 
= {} if not preorder: return None for i in range(len(inorder)): rootCan[inorder[i]] = i def build(preorder_left, preorder_right, inorder_left, inorder_right): ''' preorder_left:前序遍歷的起始座標 preorder_right:前序遍歷的終止座標 inorder_left:中序遍歷的起始座標 inorder_right:中序遍歷的終止座標 ''' if preorder_left > preorder_right: return None root = preorder[preorder_left] #前向遍歷查詢根節點 root_inder_inorder = rootCan[root] #根節點在中序遍歷中的索引 order_num = root_inder_inorder - inorder_left #左子樹長度 node = TreeNode(root) #前序遍歷中左子樹的邊界是[preorder_left + 1, preorder_left + order_num],中序遍歷左子樹的邊界的[inorder_left, inorder_left + order_num - 1]
#前序遍歷中右子樹的邊界是[preorder_left + 1 + order_num, preorder_right],中序遍歷右子樹邊界是[inorder_left + order_num + 1, inorder_right]
            node.left = build(preorder_left + 1, preorder_left + order_num, inorder_left, inorder_left + order_num - 1) #左子樹 
node.right
= build(preorder_left + 1 + order_num, preorder_right, inorder_left + order_num + 1, inorder_right) #右子樹

return node
root
= build(0, len(preorder)-1, 0, len(preorder)-1)

return root

或者不用雜湊表,就用陣列遞迴:

首先呢還是需要查詢前序遍歷的root節點在中序遍歷中的位置,然後根據這個位置,可以前序遍歷和中序遍歷中的左右子樹找出來。然後分別呼叫自身進行遞迴。

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
'''
陣列+遞迴法求解
'''
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if len(preorder) == 0:#此時連根節點都沒有 ,遞迴結束條件
            return None
        root = preorder[0]
        current_root= inorder.index(root)
        tree = TreeNode(root)
        #減小規模
        left_pre = preorder[1:current_root+1]
        right_pre = preorder[current_root+1:]
        left_in = inorder[:current_root]
        right_in = inorder[current_root+1:]
        tree.left = self.buildTree(left_pre, left_in) #呼叫自身
        tree.right = self.buildTree(right_pre, right_in)
        return tree