leetcode 劍指offer 7 重建二叉樹
阿新 • • 發佈:2020-12-26
問題描述:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。
解題思路:
前序遍歷性質: 節點按照 [ 根節點 | 左子樹 | 右子樹 ]
排序。
中序遍歷性質: 節點按照 [ 左子樹 | 根節點 | 右子樹 ]
排序。
根據以上性質,可得出以下推論:
前序遍歷的首元素 為 樹的根節點 node 的值。
在中序遍歷中搜索根節點 node 的索引 ,可將 中序遍歷 劃分為 [ 左子樹 | 根節點 | 右子樹 ] 。
根據中序遍歷中的左 / 右子樹的節點數量,可將 前序遍歷 劃分為 [ 根節點 | 左子樹 | 右子樹 ]。
以上子樹的遞推性質是 分治演算法
分治演算法解析:
遞推引數: 根節點在前序遍歷的索引root
、子樹在中序遍歷的左邊界left
、子樹在中序遍歷的右邊界right
;終止條件: 當
left > right
,代表已經越過葉節點,此時返回nullptr
;
遞推工作:
-
建立根節點
node
: 節點值為preorder[root]
; -
劃分左右子樹: 查詢根節點在中序遍歷
inorder
中的索引i
;為了提升效率,本文使用雜湊表 dic 儲存中序遍歷的值與索引的對映,查詢操作的時間複雜度為 O(1)O(1)
-
構建左右子樹: 開啟左右子樹遞迴;
根節點索引 中序遍歷左邊界 中序遍歷右邊界 左子樹 root + 1
left
i - 1
右子樹 i - left + root + 1
i + 1
right
返回值: 回溯返回 node
,作為上一層遞迴中根節點的左 / 右子節點;
題解:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { this->preorder = preorder; int i = 0; for(auto node : inorder) { this->inorder[node] = i; ++i; } return recur(0, 0, this->preorder.size() - 1); } private: vector<int> preorder; unordered_map<int, int> inorder; TreeNode* recur(int root, int left, int right) { if(left > right) return nullptr; TreeNode* node = new TreeNode(preorder[root]); int i = inorder[preorder[root]]; node->left = recur(root + 1, left, i - 1); node->right = recur(root + i - left + 1, i + 1, right); return node; } };