本题思路根据Carl大佬整理,大家感兴趣的去关注一波。如果你想提升算法能力,只要跟住代码随想录每天题目的节奏,定会融会贯通,算法能力稳稳的提升一个台阶!

一、⾸先如何根据两个顺序构造⼀个唯⼀的⼆叉树?

1、以中序和后序遍历来说:

就是以 后序数组的最后⼀个元素为切割点,先切中序数组,然后根据中序左数组,反过来在切后序数组。⼀层⼀层切下去,每次后序数组最后⼀个元素就是节点元素。

1、接下来想到用递归法
(1)、如果后序数组大小为0,说明是空节点。返回NULL。
(2)、如果不为空,取后序数组最后一个元素作为节点元素。同时再判断一下后序数组大小是不是为1,为1说明是叶子节点直接返回。
(3)、接着找到后序数组最后一个元素在中序数组的位置,作为切割点。
(4)、把中序数组切割成中序左数组和中序右数组。
(5)、把后序数组切割成后序左数组和后序右数组。
(6)、递归处理左区间和右区间。

注意事项:
1、确定切割标准,找好边界值。
2、先切中序数组,因为切割点是后序数组最后一个元素。
3、后序数组没有明确的切割点,但是要记得中序数组大小一定等于后序数组大小
现在我们把中序数组切成了中序左数组和中序右数组,那么后序数组就可以按照中序左数组的大小来切割,得到后序左数组和后序右数组。

递归法(容器分割)

class Solution{private:TreeNode* traversal(vector<int>&inorder,vector<int>&postorder) {//第一步,判断后序数组大小是否为0if(postorder.size()==0) return NULL;//第二步,找到后序遍历数组最后⼀个元素,就是当前的中间节点,接着判断是不是叶子节点int rootValue=postorder[postorder.size()-1];TreeNode* root=newTreeNode(rootValue);if(postorder.size()==1) return root;//第三步,找到中序遍历的切割点int delimiterIndex;//1从0开始,因为是容器里面装着数组for(delimiterIndex=0;delimiterIndex<inorder.size();delimiterIndex++) {if(inorder[delimiterIndex]==rootValue)break;}//第四步,切割中序数组//左闭右开区间:[0, delimiterIndex)vector<int> leftInorder(inorder.begin(),inorder.begin()+delimiterIndex);// [delimiterIndex + 1, end)vector<int> rightInorder(inorder.begin()+delimiterIndex+1,inorder.end() );// postorder舍弃末尾元素postorder.resize(postorder.size()-1);//第五步,切割后序数组//依然左闭右开,注意这⾥使⽤了左中序数组⼤⼩作为切割点,[0, leftInorder.size)vector<int> leftPostorder(postorder.begin(),postorder.begin()+leftInorder.size());// [leftInorder.size(), end)vector<int> rightPostorder(postorder.begin()+leftInorder.size(),postorder.end());root->left=traversal(leftInorder,leftPostorder);root->right=traversal(rightInorder,rightPostorder);return root;
}
public:TreeNode* buildTree(vector<int>&inorder,vector<int>&postorder{if(inorder.size()==0||postorder.size()==0) return NULL;returntraversal(inorder,postorder);}
};

如上的代码性能并不好,因为每层递归都定义了新的vector(就是数组),既耗时⼜耗空间,但上⾯的代码是最好理解的。

递归法(下表索引分割)

思路是⼀样的,只不过不⽤重复定义vector了,每次⽤下表索引来分割

class Solution{private:// 中序区间: [inorderBegin, inorderEnd),后序区间[postorderBegin, postorderEnd)TreeNode* traversal(vector<int>& inorder,int inorderbegin,int inorderend,vector<int>& postorder,int postorderbegin,int postorderend){if(postorderbegin==postorderend) return nullptr;int rootValue=postorder[postorderend-1];TreeNode* root=new TreeNode(rootValue);if(postorderend-postorderbegin==1) return root;//找到分割点在中序数组的位置int delimiterIndex;for(delimiterIndex=inorderbegin;delimiterIndex<inorderend;delimiterIndex++){ ///1 ,注意标记法的开始和结束if(inorder[delimiterIndex]==rootValue) break;}//切割中序数组//中序左数组,左闭右开[leftInorderBegin, leftInorderEnd)int leftInorderbegin=inorderbegin;//中序左数组的开始位置int leftInorderend=delimiterIndex;//中序左数组结束位置//中序右数组,左闭右开[rightInorderBegin, rightInorderEnd)int rightInorderbegin=delimiterIndex+1;//中序右数组开始位置int rightInorderend=inorderend;//根据中序左数组大小切割后序数组//后序左数组,左闭右开[leftPostorderBegin, leftPostorderEnd)int leftPostorderbegin=postorderbegin;int leftPostorderend=postorderbegin+(delimiterIndex-inorderbegin);///2//后序右数组,左闭右开[rightPostorderBegin, rightPostorderEnd)int rightPostorderbegin=postorderbegin+(delimiterIndex-inorderbegin);///3int rightPostorderend=postorderend-1;///4 排除最后⼀个元素,已经作为节点了root->left=traversal(inorder,leftInorderbegin,leftInorderend,postorder,leftPostorderbegin,leftPostorderend);root->right=traversal(inorder,rightInorderbegin,rightInorderend,postorder,rightPostorderbegin,rightPostorderend);return root;}
public:TreeNode* buildTree(vector<int>&inorder,vector<int>& postorder){if(inorder.size()==NULL||postorder.size()==NULL) return nullptr;return traversal(inorder,0,inorder.size(),postorder,0,postorder.size());}
};

2、以前序和中序遍历

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {private:TreeNode* traversal(vector<int>& preorder,int preorderBegin,int preorderEnd,vector<int>& inorder,int inorderBegin,int inorderEnd ){if(preorderBegin==preorderEnd) return NULL;int rootValue=preorder[preorderBegin];TreeNode* root=new TreeNode(rootValue);if(preorderEnd-preorderBegin==1)  return root;int delimiterIndex;for(delimiterIndex=inorderBegin;delimiterIndex<inorderEnd;delimiterIndex++){if(inorder[delimiterIndex]==rootValue) break;}//切割中序数组int leftInorderBegin=inorderBegin;int leftInorderEnd=delimiterIndex;int rightInorderBeigin=delimiterIndex+1;int rightInorderEnd=inorderEnd;//切割前序数组int leftPreorderBegin=preorderBegin+1;int leftPreorderEnd=preorderBegin+(delimiterIndex-inorderBegin)+1;int rightPreorderBeigin=preorderBegin+(delimiterIndex-inorderBegin)+1;int rightPreorderEnd=preorderEnd;root->left=traversal(preorder,leftPreorderBegin,leftPreorderEnd,inorder,leftInorderBegin,leftInorderEnd);root->right=traversal(preorder,rightPreorderBeigin,rightPreorderEnd,inorder,rightInorderBeigin,rightInorderEnd);return root;}
public:TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {if(preorder.size()==NULL||inorder.size()==NULL) return NULL;return traversal(preorder,0,preorder.size(),inorder,0,inorder.size());}
};

如何根据两个顺序构造⼀个唯⼀的⼆叉树?相关推荐

  1. 数据结构笔记:二叉树的构造(根据遍历顺序构造二叉树)

    目录 给出先序遍历序列和中序遍历序列可以唯一确定二叉树 给出后序遍历序列和中序遍历序列可以唯一确定二叉树 题: 给出先序遍历序列和中序遍历序列可以唯一确定二叉树 给出后序遍历序列和中序遍历序列可以唯一 ...

  2. 数据结构——二叉树的修改与构造

    数据结构--二叉树的修改与构造 一.修改二叉树 226. 翻转二叉树 1.前/后序递归 2.广度优先搜索迭代 3.拓展:修改中序遍历 / 中序统一迭代写法 114. 二叉树展开为链表 二.构造二叉树 ...

  3. LeetCode专题:树与回溯(完结,已更50题)

    目录 LeetCode二叉树的基本遍历(难): 写在前面: 前序遍历: Morris遍历: 中序遍历: Morris遍历: 后序遍历: Morris遍历: 二叉树前中后迭代方式同一写法: 鸣谢: Le ...

  4. 虚继承c语言例子,C/C++ 多继承{虚基类,虚继承,构造顺序,析构顺序}

    C/C++:一个基类继承和多个基类继承的区别 1.对多个基类继承会出现类之间嵌套时出现的同名问题,如果同名变量或者函数出现不在同一层次,则底层派生隐藏外层比如继承基类的同名变量和函数,不会出现二义性, ...

  5. 第十章 C++编程之构造顺序

    第十章 C++编程之构造顺序 10.1 解释概念 简单说,构造函数就是在定义某个类的时候会调用的一个函数,默认构造不带参,其余构造函数可以自己实现. 10.2 示例代码 1.示例代码 #include ...

  6. C++类变量构造和析构顺序

    文章目录 继承关系上构造析构顺序 同一级别的构造顺序 析构的顺序则刚好是构造顺序的逆序 继承关系上构造析构顺序 有类静态成员变量优先构造静态变量 与声明的顺序无关,与继承关系也无关,只是按照定义的先后 ...

  7. C++构造函数及析构函数的调用顺序

    简单来说,其构造函数的顺序就一句话: 基类构造函数 -> 成员的构造函数 -> 构造函数体内语句 看下面一个代码示例: #include <iostream>using nam ...

  8. 中石油训练赛 - Insertion Order(二叉搜索树+构造)

    题目大意:构造出一个长度为 n 的排列,使得按照这个顺序构造出的二叉搜索树的高度为 k 题目分析:知道 n 的大小后不难算出其可以构造的二叉搜索树高度的可行范围,下限是一棵满二叉树,这个利用倍增很快就 ...

  9. Python treelib库创建多叉树的用法介绍

    Python treelib库创建多叉树的用法介绍 treelib 库是一个 Python 的第三方库.这个库实现了一些多叉树相关的常用方法. 一.安装treelib pip install tree ...

最新文章

  1. 阿里Java开发手册——如何优化数据库?
  2. 电量计在手持设备中的实现
  3. 报警服务器物理内存,从内存告警谈ESXi主机内存管理——内存构成
  4. ie浏览器打字不显示文字框命令
  5. 那些一心想要离开 BAT 的人,后来怎么样了?
  6. java对list里面按照分数排名_近3年全国高校高考录取分数线排名,600分以上高校55所...
  7. python语言程序设计实践教程上海交通大学出版社的答案_高等教育出版社出版社c语言程序设计实践教程习题参考答案...
  8. python中pip下载过慢问题
  9. TM2013自定义消息记录保存目录
  10. c语言 虚拟时钟 指针,指针式模拟时钟.doc
  11. 吾爱破解新手教程(1)- 破解,逆向,安全
  12. html中onfocus作用,HTML onfocus用法及代码示例
  13. 502粘到手上变硬了怎么办_502胶水把手黏住了怎么办
  14. linux_zsh/oh my zsh 版本检查/使用帮助(check and update)/安装最新版zsh
  15. JAVA--建立一个可输入个人信息的窗口
  16. 专享策略02 | 商品股指通用套利策略(一)
  17. P528 List接口常用实现类的对比及源码分析
  18. java中接口的优点和缺点
  19. 计算机 无法进入pe,U盘重装系统|无法进入韩博士PE系统怎么办
  20. SmallUI-小ui 前端ui组件库(好用的组件千篇一律,轻巧的组件万里挑一)

热门文章

  1. 让那些为Webkit优化的网站也能适配IE10(转载)
  2. HTML标签语义化——使用b标签,还是strong标签
  3. VC里的#define new DEBUG_NEW
  4. word通配符使用法详解
  5. Linux下GCC的安装,GCC链接外部库
  6. MySQL count(1) count(*) 比较 详解
  7. RxSwift之深入解析map操作符的底层实现
  8. LDC1000学习资料
  9. Martix工作室考核题 —— 2019-3-8 第三题
  10. 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1109:开关灯