阿里面试官问我:给两个序列如何构造一棵二叉树

167 阅读3分钟

微信搜一搜bigsai 好文第一时间分享

前言

在面试的过程中,我们经常会遇到一些数据结构相关的问题,很多经典问题百问不烂。而数据结构的问题中排序、链表、二叉树等问题又是经久不衰,这不,今天就分享一道关于经典的问题:给定两个序列如何构造一颗二叉树。

tips:遇到二叉树相关的问题,多半和递归有关系

从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。当然也是力扣105的原题

注意:你可以假设树中没有重复的元素

例如,给出

前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7]

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

分析: 给定一个前序序列和一个中序序列,且里面没有重复的元素,如何构造一和二叉树呢?我们可以先单独观察两个序列的特征:

前序遍历:遍历规则为(根,[左侧区域],[右侧区域])。 中序遍历:遍历规则为([左侧区域],根,[右侧区域])。

其中前序遍历的左侧区域和中序遍历的左侧区域包含元素的范围相同,根也是相同的。所以可以进行这样的操作:

  1. 根据前序遍历的第一个找到根节点,可以确定根
  2. 通过中序遍历找到根节点的值,这样可以知道左侧区域和右侧区域节点个数多少。
  3. 根节点左侧区域由前中序列确定的左侧区域确定,根节点的右侧节点由前中序序列的右侧区域确定。

一些操作可以借助这张图进行理解: 在这里插入图片描述

具体的实现上,可以使用一个HashMap存储中序存储的序列,避免重复计算。实现的代码为:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
   public TreeNode buildTree(int[] preorder, int[] inorder) {
		if(preorder.length==0)
			return null;
		TreeNode root=new TreeNode(preorder[0]);
		Map<Integer, Integer>map=new HashMap<Integer, Integer>();
		for(int i=0;i<inorder.length;i++)
		{
			map.put(inorder[i], i);
		}
		return buildTree(preorder,0,preorder.length-1, map,0,inorder.length-1);
    }

	private TreeNode buildTree(int[] preorder, int preStart, int preEnd, Map<Integer, Integer> map, int inStart, int inEnd) {
		// TODO Auto-generated method stub
		if(preEnd<preStart||inEnd<inStart)
			return null;
		TreeNode node=new TreeNode(preorder[preStart]);
		int i=map.get(preorder[preStart]);//节点的值
		
		int leftlen=i-inStart;//左面的长度
		node.left=buildTree(preorder, preStart+1, preStart+1+leftlen, map, inStart, i-1);
		node.right=buildTree(preorder, preStart+leftlen+1,preEnd, map, i+1, inEnd);
		return node;		
	}
}

从中序与后序遍历序列构造二叉树

根据一棵树的中序遍历与后序遍历构造二叉树,力扣106题

注意:你可以假设树中没有重复的元素。

例如,给出

中序遍历 inorder = [9,3,15,20,7] 后序遍历 postorder = [9,15,7,20,3]

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

分析: 有了上面的分析,那么通过一个后序遍历和中序遍历去构造一棵二叉树,其实原理和前面的也是一样的。

后序遍历:遍历规则为([左侧区域],[右侧区域],根)。 中序遍历:遍历规则为([左侧区域],根,[右侧区域])。

在这里插入图片描述 具体实现的代码为:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
   public TreeNode buildTree(int[] inorder,int[] postorder) {
		if(postorder.length==0)
			return null;
		Map<Integer, Integer>map=new HashMap<Integer, Integer>();
		for(int i=0;i<inorder.length;i++)
		{
			map.put(inorder[i], i);
		}
		return buildTree(postorder,0,postorder.length-1, map,0,inorder.length-1);
    }

	private TreeNode buildTree(int[] postorder, int postStart, int postEnd, Map<Integer, Integer> map, int inStart, int inEnd) {
		// TODO Auto-generated method stub
		if(postEnd<postStart||inEnd<inStart)
			return null;
		TreeNode node=new TreeNode(postorder[postEnd]);
		int i=map.get(postorder[postEnd]);
		
			
		int leftlen=i-inStart;
		
		node.left=buildTree(postorder, postStart,postStart+leftlen-1, map, inStart, i-1);
		node.right=buildTree(postorder, postStart+leftlen,postEnd-1, map, i+1, inEnd);           return node;		
	}
}

原创不易,bigsai请你帮两件事帮忙一下:

点赞支持一下, 您的肯定是我在平台创作的源源动力。

微信搜索「bigsai」,回复bigsai白嫖电子书,咱们下次再见!