算法设计与分析课作业【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);
  		}
    }
};

跑的速度也不错,在leetcode上跑的时间如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值