力扣-105-從前序遍歷與中序遍歷序列構造二叉樹
阿新 • • 發佈:2020-08-02
傳送門(題目要求每個數字不重複)
題目分析:遞迴
對於任意一顆樹而言,前序遍歷的形式總是:[ 根節點, [左子樹的前序遍歷結果], [右子樹的前序遍歷結果] ]
即根節點總是前序遍歷中的第一個節點。而中序遍歷的形式總是:[ [左子樹的中序遍歷結果], 根節點, [右子樹的中序遍歷結果] ]
如果我們在中序遍歷中定位找到根節點,那我們就可以分別知道根節點的左子樹和右子樹的數目,也就能在前序遍歷中找到對應的左子樹和右子樹,如上圖中用括號進行定位。
這樣一來題目就分解為:根據左子樹的中序遍歷和前序遍歷,確定左子樹的二叉樹形式;右子樹也是這樣。這明顯是一個遞迴問題。
這裡有一個可以優化的地方,對於前序遍歷中的根節點,如果每次都遍歷一遍中序遍歷,找到它在中序遍歷中的位置,這樣的複雜度會很高。我們可以建立一個HashMap,建立 值<-->索引的map,遍歷一遍中序遍歷即可。具體程式碼如下:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ #include <map> using namespace std; class Solution { private: map<int, int> Index;public: TreeNode* MyBuildTree(const vector<int>& preorder, const vector<int>& inorder, int preLeft, int preRight, int inLeft, int inRight){ if(preLeft > preRight) return NULL; int preRoot = preLeft; int pIndex = Index[preorder[preRoot]]; TreeNode* root = new TreeNode(preorder[preRoot]); int deta = pIndex - inLeft; //遞迴,建立左子樹 root->left = MyBuildTree(preorder, inorder, preLeft + 1, preLeft + deta, inLeft, pIndex - 1); //遞迴,建立右子樹 root->right = MyBuildTree(preorder, inorder,preLeft + deta + 1, preRight, pIndex + 1, inRight); return root; } TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { int num = inorder.size(); for(int i = 0; i < num; i++){ Index[inorder[i]] = i; //將前序遍歷中每個節點在中序遍歷中的位置找到 } return MyBuildTree(preorder, inorder,0, num - 1, 0, num - 1); //返回連結串列的頭結點 } };