1. 程式人生 > 實用技巧 >力扣-105-從前序遍歷與中序遍歷序列構造二叉樹

力扣-105-從前序遍歷與中序遍歷序列構造二叉樹

傳送門(題目要求每個數字不重複)

題目分析:遞迴

對於任意一顆樹而言,前序遍歷的形式總是:[ 根節點, [左子樹的前序遍歷結果], [右子樹的前序遍歷結果] ]

即根節點總是前序遍歷中的第一個節點。而中序遍歷的形式總是:[ [左子樹的中序遍歷結果], 根節點, [右子樹的中序遍歷結果] ]

如果我們在中序遍歷中定位找到根節點,那我們就可以分別知道根節點的左子樹和右子樹的數目,也就能在前序遍歷中找到對應的左子樹和右子樹,如上圖中用括號進行定位。

這樣一來題目就分解為:根據左子樹的中序遍歷和前序遍歷,確定左子樹的二叉樹形式;右子樹也是這樣。這明顯是一個遞迴問題。

這裡有一個可以優化的地方,對於前序遍歷中的根節點,如果每次都遍歷一遍中序遍歷,找到它在中序遍歷中的位置,這樣的複雜度會很高。我們可以建立一個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); //返回連結串列的頭結點 } };