给定二叉树的前序遍历结果,输出所有可能的中序遍历的结果
2018-03-30 16:36
483 查看
题目如下:给出一个二叉树的前序遍历,输出这个树所有可能的中序遍历(有时也会可能会是后序遍历)
对应于一棵二叉树的前序遍历,我们知道,前序遍历的第一个节点,一定是根节点。所以,我们可以很容易的找出根节点,剩下的部分呢,是左子树和右子树节点在一起了,本题的难点就在于,你如何去将前序遍历的结果中除去根节点部分的其余节点分为左右子树的节点。暴力一些就是慢慢拆。以前序遍历{1,2,3}为例。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201803/e0bca3bb43eb768794643b79f1014e51)
因为节点较少,分析起来也很直观,所以我们可以分为以上几种情况,对于case1和case3,我们可以看出,case1中的2,3又可以存在两种不同的情况,case3中的左子树同理。可以分为以下5中情况。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201803/b76cfa13017883a81c2c713da68cc783)
这时候可以直接上代码了吧。package oj;
import java.util.ArrayList;
import java.util.List;
public class Solution2 {
public static void main(String[] args) {
int []preorder= {1,2,3,4,5};
List<BinaryTree> trees=GetAllTrees(preorder, 0, preorder.length-1);
//System.out.println(trees);
for(BinaryTree tr:trees)
{
tr.PrintInOrder();
}
}
/*
* 我们考虑一下上面的思路。
* 首先我们需要先找到整棵二叉树的根节点,然后将剩下的节点进行划分,
* 划分的方法无非就是a个节点作为左子树,n-a-1个节点作为右子树。
* 我们选取一个ArrayList来存储所有可能的结构,原因是这一数据结构
* 方便我们来 append/remove
*/
static List<BinaryTree> GetAllTrees(int[]preorder, int start,int end){
//resultTree用来接收所有的可能的结果,并返回
List<BinaryTree>resultTree=new ArrayList<>();
if(start>end||start<0||end>=preorder.length)
{
resultTree.add(null);
return resultTree;
}
if(start==end)
{
//前序遍历只给定一个节点的情况,这时直接将其添加到resultTree中,返回即可
resultTree.add(new BinaryTree(preorder[start]));
return resultTree;
}
/*好吧,最头疼的代码要开始了
* 首先,我们的左右子树节点的个数是从0~n-1的,所以我们可以记左节点个数为i,右节点的个数为n-1-i
*/
for(int i=-1;i< end-start;i++) {
//注意i的值是从-1开始的,意味着左子树可以为空,左子树时start+1+i的部分,
//右子树则从start+1+i+1开始。一直到end结束。就这样递归着就可以将左右子树根据i值得不同划分好。
List<BinaryTree> leftChlidren=GetAllTrees(preorder, start+1, start+1+i);
List<BinaryTree> rightChildren=GetAllTrees(preorder, start+1+i+1, end);
//这时候根据i的值划分好左右子树,需要我们分配相应的树形结构
for(BinaryTree leftpart:leftChlidren) {
for(BinaryTree rightpart:rightChildren) {
BinaryTree tempRoot=new BinaryTree(preorder[start]);
tempRoot.left=leftpart;
tempRoot.right=rightpart;
resultTree.add(tempRoot);
}
}
}
return resultTree;
}
}
//首先,我们先定义我们的简单二叉树结构
class BinaryTree{
int val;
BinaryTree left;
BinaryTree right;
public BinaryTree(int k)
{
this.val=k;
}
//同样我们需要输出中序遍历的结果
public void PrintInOrder()
{
InOrderTraversal(this);
System.out.println();//输出换行
}
private void InOrderTraversal(BinaryTree tree) {
if(tree==null)return;
InOrderTraversal(tree.left);
System.out.print(tree.val);
InOrderTraversal(tree.right);
}
}
另一个问题如下:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。(剑指offer第六题)
借用他的思路吧,反正我也是这么想的
![](https://oscdn.geek-share.com/Uploads/Images/Content/201803/ef9fdba1f8499038e7ba8a8d03687766)
根据前序遍历的特点,我们知道根结点为1
观察中序遍历。其中root节点G左侧的472必然是root的左子树,G右侧的5386必然是root的右子树。
观察左子树472,左子树的中的根节点必然是大树的root的leftchild。在前序遍历中,大树的root的leftchild位于root之后,所以左子树的根节点为2。
同样的道理,root的右子树节点5386中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。
观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。
该步递归的过程可以简洁表达如下:
确定根,确定左子树,确定右子树。
在左子树中递归。
在右子树中递归。
打印当前根。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201803/1b0f86c3a6365accc34e1ea8aae66405)
public class Solution {
// 给定前序和中序遍历的结果
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
TreeNode root = reConstructBinaryTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
return root;
}
private TreeNode reConstructBinaryTree(int[] pre, int startPre, int endPre, int[] in, int startIn, int endIn) {
if (startPre > endPre || startIn > endIn)
return null;
TreeNode root = new TreeNode(pre[startPre]);
for (int i = startIn; i <= endIn; i++) {
if (in[i] == pre[startPre]) {// 从这里开始划分好二叉树中的左子树和右子树
// 前序中,从startPre+1位置开始,到startPre+(i-startIn)的部分是左子树。
root.left = reConstructBinaryTree(pre, startPre + 1, startPre + i - stratIn, in, startIn, i - 1);
root.right = reConstructBinaryTree(pre, startPre + i - startIn + 1, endPre, in, i + 1, endIn);
break;
}
}
return root;
}
}
溜了溜了,一下午写了两道题解。没干啥正事,啊啊啊啊啊好慌啊
对应于一棵二叉树的前序遍历,我们知道,前序遍历的第一个节点,一定是根节点。所以,我们可以很容易的找出根节点,剩下的部分呢,是左子树和右子树节点在一起了,本题的难点就在于,你如何去将前序遍历的结果中除去根节点部分的其余节点分为左右子树的节点。暴力一些就是慢慢拆。以前序遍历{1,2,3}为例。
因为节点较少,分析起来也很直观,所以我们可以分为以上几种情况,对于case1和case3,我们可以看出,case1中的2,3又可以存在两种不同的情况,case3中的左子树同理。可以分为以下5中情况。
这时候可以直接上代码了吧。package oj;
import java.util.ArrayList;
import java.util.List;
public class Solution2 {
public static void main(String[] args) {
int []preorder= {1,2,3,4,5};
List<BinaryTree> trees=GetAllTrees(preorder, 0, preorder.length-1);
//System.out.println(trees);
for(BinaryTree tr:trees)
{
tr.PrintInOrder();
}
}
/*
* 我们考虑一下上面的思路。
* 首先我们需要先找到整棵二叉树的根节点,然后将剩下的节点进行划分,
* 划分的方法无非就是a个节点作为左子树,n-a-1个节点作为右子树。
* 我们选取一个ArrayList来存储所有可能的结构,原因是这一数据结构
* 方便我们来 append/remove
*/
static List<BinaryTree> GetAllTrees(int[]preorder, int start,int end){
//resultTree用来接收所有的可能的结果,并返回
List<BinaryTree>resultTree=new ArrayList<>();
if(start>end||start<0||end>=preorder.length)
{
resultTree.add(null);
return resultTree;
}
if(start==end)
{
//前序遍历只给定一个节点的情况,这时直接将其添加到resultTree中,返回即可
resultTree.add(new BinaryTree(preorder[start]));
return resultTree;
}
/*好吧,最头疼的代码要开始了
* 首先,我们的左右子树节点的个数是从0~n-1的,所以我们可以记左节点个数为i,右节点的个数为n-1-i
*/
for(int i=-1;i< end-start;i++) {
//注意i的值是从-1开始的,意味着左子树可以为空,左子树时start+1+i的部分,
//右子树则从start+1+i+1开始。一直到end结束。就这样递归着就可以将左右子树根据i值得不同划分好。
List<BinaryTree> leftChlidren=GetAllTrees(preorder, start+1, start+1+i);
List<BinaryTree> rightChildren=GetAllTrees(preorder, start+1+i+1, end);
//这时候根据i的值划分好左右子树,需要我们分配相应的树形结构
for(BinaryTree leftpart:leftChlidren) {
for(BinaryTree rightpart:rightChildren) {
BinaryTree tempRoot=new BinaryTree(preorder[start]);
tempRoot.left=leftpart;
tempRoot.right=rightpart;
resultTree.add(tempRoot);
}
}
}
return resultTree;
}
}
//首先,我们先定义我们的简单二叉树结构
class BinaryTree{
int val;
BinaryTree left;
BinaryTree right;
public BinaryTree(int k)
{
this.val=k;
}
//同样我们需要输出中序遍历的结果
public void PrintInOrder()
{
InOrderTraversal(this);
System.out.println();//输出换行
}
private void InOrderTraversal(BinaryTree tree) {
if(tree==null)return;
InOrderTraversal(tree.left);
System.out.print(tree.val);
InOrderTraversal(tree.right);
}
}
另一个问题如下:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。(剑指offer第六题)
借用他的思路吧,反正我也是这么想的
根据前序遍历的特点,我们知道根结点为1
观察中序遍历。其中root节点G左侧的472必然是root的左子树,G右侧的5386必然是root的右子树。
观察左子树472,左子树的中的根节点必然是大树的root的leftchild。在前序遍历中,大树的root的leftchild位于root之后,所以左子树的根节点为2。
同样的道理,root的右子树节点5386中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。
观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。
该步递归的过程可以简洁表达如下:
确定根,确定左子树,确定右子树。
在左子树中递归。
在右子树中递归。
打印当前根。
public class Solution {
// 给定前序和中序遍历的结果
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
TreeNode root = reConstructBinaryTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
return root;
}
private TreeNode reConstructBinaryTree(int[] pre, int startPre, int endPre, int[] in, int startIn, int endIn) {
if (startPre > endPre || startIn > endIn)
return null;
TreeNode root = new TreeNode(pre[startPre]);
for (int i = startIn; i <= endIn; i++) {
if (in[i] == pre[startPre]) {// 从这里开始划分好二叉树中的左子树和右子树
// 前序中,从startPre+1位置开始,到startPre+(i-startIn)的部分是左子树。
root.left = reConstructBinaryTree(pre, startPre + 1, startPre + i - stratIn, in, startIn, i - 1);
root.right = reConstructBinaryTree(pre, startPre + i - startIn + 1, endPre, in, i + 1, endIn);
break;
}
}
return root;
}
}
溜了溜了,一下午写了两道题解。没干啥正事,啊啊啊啊啊好慌啊
相关文章推荐
- 剑指offer给定二叉树,求中序遍历的下一个 节点,前序遍历,后序遍历扩展
- Python练手之根据前序和中序&根据中序和后序重建二叉树,输出前序、中序和后序遍历结果
- 由树的前序遍历,中序遍历建立一颗二叉树,并以后续遍历的方式输出其元素
- [c++]已知二叉树的前序遍历与中序遍历结果(二叉树中不含重复数字),重构二叉树
- 给定一个字符串,字符串中的*可以替换成0或1,输出所有可能的结果
- 二叉树先序遍历中序遍历结果得出该树,并以后序遍历形式输出
- 面试题 二叉树的前序遍历,中序遍历,后序遍历(递归实现)
- 关于二叉树的前序遍历、中序遍历、删除元素、插入元素
- 根据树的前序遍历与中序遍历构建二叉树
- 判断一个数列是不是搜索二叉树后续遍历输出的结果
- 输入一个数组,判断该数组是否是某二叉树的前序遍历结果
- 给定入栈顺序,输出所有可能的出栈情况,并判断给定的序列是否为正确的输出序列
- 对于已知二叉树的中序遍历和后序遍历如何求二叉树的的前序遍历
- 在1、2、3...9(保持这个顺序)之间可任意放+或者-或者不放,使其结果等于100,输出所有可能的放法。js写法
- 已知二叉树的先序、中序遍历序列,求其后序遍历结果。(hduoj1710)
- 已知二叉树的前序遍历结果和中序遍历结果,请重建原来的二叉树
- 构造二叉树的抽象数据类型对于给定的先序序列和中序序列,构造二叉树,并按层输出所有结点内容,要求每层结点输出一行按层输出上述二叉树所表示的森林的所有结点内容
- 构建二叉树(据前序遍历结果)--- 前序遍历二叉树(递归与非递归)
- 二叉树的前序遍历、中序遍历和后序遍历及其算法
- 给定一颗二叉树的前序序列,求所有可能的中序序列