劍指 Offer 07. 重建二叉樹重建二叉樹
阿新 • • 發佈:2020-08-04
- 題目描述
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。
例如,給出
前序遍歷 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找到中序遍歷中左子樹和右子樹的:[ 左子樹 | 根節點 | 右子樹 ]
根據中序遍歷的左右子樹的節點數量,可將前序遍歷劃分為[ 根節點 | 左子樹 | 右子樹 ]
根據子樹特點,我們可以通過同樣的方法對左(右)子樹進行劃分,每輪可確認三個節點的關係。此遞推性質讓我們聯想到用遞迴方法處理。
此時需要理解的是:
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