1. 程式人生 > 實用技巧 >leetcode 劍指offer 7 重建二叉樹

leetcode 劍指offer 7 重建二叉樹

問題描述:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。

解題思路:

前序遍歷性質: 節點按照 [ 根節點 | 左子樹 | 右子樹 ] 排序。
中序遍歷性質: 節點按照 [ 左子樹 | 根節點 | 右子樹 ] 排序。

根據以上性質,可得出以下推論:

前序遍歷的首元素 為 樹的根節點 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;
    }
};