1. 程式人生 > >演算法設計與分析課作業【week3】leetode--105. Construct Binary Tree from Preorder and Inorder Traversal

演算法設計與分析課作業【week3】leetode--105. Construct Binary Tree from Preorder and Inorder Traversal

題目

Given preorder and inorder traversal of a tree, construct the binary tree.

Note: You may assume that duplicates do not exist in the tree.

For example, given

preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]

Return the following binary tree:

    3
   / \
  9  20
    /  \
   15   7

題目要求是利用二叉樹的先序和中序遍歷的陣列,來構建二叉樹。

如果不瞭解二叉樹的先序和中序遍歷的話,別人的部落格都有介紹可以先了解下。這裡我們直接以知道遍歷方法來講述。

樹的先序遍歷先輸出樹的根節點,再輸出左子節點,再輸出右子節點。

樹的中序遍歷則是先輸出左子節點,再輸出根節點,最後輸出右子節點。

我們先由例子來找規律,由先序遍歷的陣列開始一個一個來,首先是3,由於先序遍歷是先輸出根節點的,所以先序遍歷陣列的第一個元素便是這棵二叉樹的根節點,即根節點是3。

然後我們看到3在中序遍歷陣列的第2個元素的位置,我們知道樹的中序遍歷先輸出左子節點,再輸出根節點,通俗的說就是先左,再中,後右。那麼在3之前輸出的就屬於3的左子樹,在3後面則屬於3的右子樹。所以由中序遍歷陣列我們可以初步得到以下樹形:

     3
    / \
 (9)(15,20, 7)

此時我們看先序遍歷陣列的第二個元素,第二個元素是9,也就是說9是3的左子樹的根節點,此時3的左子樹也只有9。所以此時左邊結束。

    3
   / \
  9  (15,20,7)

接下來我們看先序遍歷陣列的第三個元素,是20,也就是說20是3的右子樹的根節點,那麼我們再看20在中序遍歷陣列的位置,此時我們需要確定是3的右子樹,所以只需要看3的右子樹部分的數字,也就是看15,20,7這3個數的相對位置,可以看到15在20前輸出(在20左邊),7在20之後(在20後邊),也就是說,15是以20為根節點的左子樹的部分,而7則是以20為根節點的右子樹的部分。

此時我們便已得出我們所需要的二叉樹了。

    3
   / \
  9  20
    /  \
   15   7

總結一下步驟就是:

  1. 從頭到尾依次拿出先序遍歷陣列的一個元素,設為A。
  2. 確定該元素A在中序遍歷陣列的位置。在中序遍歷陣列中,位於元素A的左邊的元素則在樹中屬於元素A的左子樹,位於元素A的右邊的元素則在樹中屬於元素A的左子樹。
  3. 重複1,2直至所有元素排列完成。

這種特性用遞迴的方式就能很好的實現,C++程式碼如下:

/**
 * 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) {
      /*利用map來儲存樹元素在中序遍歷陣列的位置,
        這樣取位置的時候不用每次遍歷一下陣列來獲得*/
      map<int, int> nodesIndex;
      int index = 0;
      for (int i = 0; i < inorder.size(); ++i) {
      	nodesIndex[inorder[i]] = i;
      }
      if (preorder.size() == 0) return NULL;
      TreeNode* head = new TreeNode(preorder[0]);
      if (nodesIndex[preorder[0]] > 0) {
      	helpToBuildTree(preorder, nodesIndex, head, true, ++index, 0,         
          nodesIndex[preorder[0]] - 1);
      }
      if (nodesIndex[preorder[0]] < preorder.size() - 1) {
      	helpToBuildTree(preorder, nodesIndex, head, false, ++index, 
          nodesIndex[preorder[0]] + 1, preorder.size() - 1);
      }
      return head;
    }

    void helpToBuildTree(vector<int>& preorder, map<int, int>& nodesIndex, 
           TreeNode* node, bool left, int& index, int front, int latter) {
    	TreeNode* tmp;
    	if (left) {
    		node->left = new TreeNode(preorder[index]);
    		tmp = node->left;
    	}
    	else {
    		node->right = new TreeNode(preorder[index]);
    		tmp = node->right;
    	}
    	int inorderIndex = nodesIndex[preorder[index]];
  		if (inorderIndex > front) {
  			helpToBuildTree(preorder, nodesIndex, tmp, true, ++index, 
          front, inorderIndex - 1);
  		}
  		if (inorderIndex < latter) {
  			helpToBuildTree(preorder, nodesIndex, tmp, false, ++index, 
          inorderIndex +  1, latter);
  		}
    }
};