根據一棵樹的前序遍歷與中序遍歷構造二叉樹。
注意:
你可以假設樹中沒有重複的元素。
例如,給出
前序遍歷 preorder = [3,9,20,15,7]
中序遍歷 inorder = [9,3,15,20,7]
返回如下的二叉樹:
3
/ \9 20
/ \
15 7
方法一:遞迴
思路對於任意一顆樹而言,前序遍歷的形式總是
[ 根節點, [左子樹的前序遍歷結果], [右子樹的前序遍歷結果] ]
即根節點總是前序遍歷中的第乙個節點。而中序遍歷的形式總是
[ [左子樹的中序遍歷結果], 根節點, [右子樹的中序遍歷結果] ]
只要我們在中序遍歷中定位到根節點,那麼我們就可以分別知道左子樹和右子樹中的節點數目。由於同一顆子樹的前序遍歷和中序遍歷的長度顯然是相同的,因此我們就可以對應到前序遍歷的結果中,對上述形式中的所有左右括號進行定位。
這樣以來,我們就知道了左子樹的前序遍歷和中序遍歷結果,以及右子樹的前序遍歷和中序遍歷結果,我們就可以遞迴地對構造出左子樹和右子樹,再將這兩顆子樹接到根節點的左右位置。
細節在中序遍歷中對根節點進行定位時,一種簡單的方法是直接掃瞄整個中序遍歷的結果並找出根節點,但這樣做的時間複雜度較高。我們可以考慮使用雜湊對映(hashmap)來幫助我們快速地定位根節點。對於雜湊對映中的每個鍵值對,鍵表示乙個元素(節點的值),值表示其在中序遍歷中的出現位置。在構造二叉樹的過程之前,我們可以對中序遍歷的列表進行一遍掃瞄,就可以構造出這個雜湊對映。在此後構造二叉樹的過程中,我們就只需要 o(1)o(1) 的時間對根節點進行定位了。
class solution
// 前序遍歷中的第乙個節點就是根節點
int preorder_root = preorder_left;
// 在中序遍歷中定位根節點
int inorder_root = index[preorder[preorder_root]];
// 先把根節點建立出來
treenode* root = new treenode(preorder[preorder_root]);
// 得到左子樹中的節點數目
int size_left_subtree = inorder_root - inorder_left;
// 遞迴地構造左子樹,並連線到根節點
// 先序遍歷中「從 左邊界+1 開始的 size_left_subtree」個元素就對應了中序遍歷中「從 左邊界 開始到 根節點定位-1」的元素
root->left = mybuildtree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
// 遞迴地構造右子樹,並連線到根節點
// 先序遍歷中「從 左邊界+1+左子樹節點數目 開始到 右邊界」的元素就對應了中序遍歷中「從 根節點定位+1 到 右邊界」的元素
root->right = mybuildtree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
return root;
}treenode* buildtree(vector& preorder, vector& inorder)
return mybuildtree(preorder, inorder, 0, n - 1, 0, n - 1);
}};
LeetCode第146題解析
運用你所掌握的資料結構,設計和實現乙個 lru 最近最少使用 快取機制。它應該支援以下操作 獲取資料 get 和 寫入資料 put 獲取資料 get key 如果關鍵字 key 存在於快取中,則獲取關鍵字的值 總是正數 否則返回 1。寫入資料 put key,value 如果關鍵字已經存在,則變更其...
LeetCode第15題解析
給你乙個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c 使得 a b c 0 請你找出所有滿足條件且不重複的三元組。注意 答案中不可以包含重複的三元組。示例 給定陣列 nums 1,0,1,2,1,4 滿足要求的三元組集合為 1,0,1 1,1,2 class so...
LeetCode第641題解析
設計實現雙端佇列。你的實現需要支援以下操作 mycirculardeque k 建構函式,雙端佇列的大小為k。insertfront 將乙個元素新增到雙端佇列頭部。如果操作成功返回 true。insertlast 將乙個元素新增到雙端佇列尾部。如果操作成功返回 true。deletefront 從雙...