二叉树的基础题目学习(EPI)
1.判断是个二叉树是不是平衡二叉树。
二叉树的定义都是利用递归的方法,所以二叉树有着天然的递归属性。所以一般情况下,递归解决二叉树问题中,递归解法比较简洁。平衡二叉树的定义是左子树和右子树均是平衡二叉树,并且左子树和右子树的高度差不超过1,三个条件缺一不可。
根据递归的定义,递归实现起来需要返回子树的高度,又要返回子树是否平衡的属性,所以判断平衡二叉树的递归算法需要传会两个参数,所以把递归函数原型定义为int balancedTree(TreeNode* root, bool &isBalanced)形式,返回值返回高度,其中引用形参也当做返回值代表子树是否平衡,这样实现起来比较容易了。(二叉树中好多算法递归均需要这种返回多个变量的递归写法,可以练习一下。举印象深刻的两个类似的:a.二叉树中最大路径(路径定义从任意一节点至任意另一节点),b.最近公共祖先问题,有更多的欢迎补充)。
一种开阔视野的方法:一种将空间复杂度近一步降低的方法是采用先序遍历,然后利用一个全局变量实时的记录stack的最大深度。《计算机编程艺术》第三卷,排序和查找460页证明了n个节点的平衡树的高度不会超过hn=1.4405lg(n/2+3)-0.3277。如果遍历的时候栈的高度超过了这个高度,则这颗树为不平衡的树。
2.首先,设定一个概念,如果一棵树的左子树的节点数量和右子树的节点数量的差的绝对值不大于k,则该节点不是k平衡的。
题目:给定一个二叉树,找出二叉树中一个不是k平衡的节点,且此节点的后继节点均是k平衡的节点。
递归的查找即可,设定一个全局节点变量,初始化为NULL,递归中寻找到节点之后赋值给全局节点变量,递归函数中如果全局变量不为NULL,直接返回。递归函数返回值为当前树的节点数量即可。当前树的节点的数量=左子树节点数量+右子树节点数量+1,递归结束条件为节点未NULL,返回节点数量0。唯一赋值全局节点变量的地方就是第一次出现左子树与右子树差值绝对值超过k的时候,这时候沿着递归路径一路返回,全局变量及为所求。
3.判断二叉树是不是镜像的。
leetcode中存在原题,比较容易,同样利用递归判断,不过起始条件为左子树节点和右子树节点。递归函数isSymmetric(TreeNode *left, TreeNode *right),首先根节点必须相等,其次必须满足继续递归isSymmetric(left->right,right->let)&&isSymmetric(left->left,right->right),三个条件同时满足,则才能够判断是镜像树。递归代码很简洁。
4.实现一个二叉树加锁的机制,限制条件是如果一个节点的后继节点或者祖先节点已经被锁定,则该节点不能够被锁定。实现isLock(),lock(),和unlock()操作,时间复杂度分别限制为O(1),O(h),O(h),其中h为树的高度。假设此二叉树存在指向父节点的指针。
每个节点添加一个标志位,简单实现O(1)的isLock()操作。
另外就是维护lock(),unlock()的时候维护节点的标志位操作了。加锁和解锁的时候需要考虑祖先,也需要考虑孩子,祖先可以在O(h)的时间复杂度内遍历获取状态。孩子节点如果逐个考虑可能需要O(n)了。所以不能逐个遍历,
这里可以在节点中继续保存一个变量,其为孩子节点是否被锁。该变量在lock的时候向上回溯祖先的时候逐个设置标志位即可。
所以解锁的时候进行相应的操作,解锁的时候需要释放其祖先节点中孩子加锁的标志,并且也需要更改是否锁定的标志。
5.给定一个存在父节点指针的二叉树表示,使用O(1)的额外空间遍历二叉树。(先序,中序,后序),不能修改树的结构。
Morris方法能够O(1)的空间复杂度实现二叉树的遍历,但是遍历过程中需要临时改变树形结构,所以该遍历算法不是线程安全的。
题目存在父节点指针,所以不需要利用栈来进行回溯,可以利用父节点指针回溯,所以可以达到O(1)的时间复杂度。
算法模板参考利用栈实现的后续遍历,设置当前节点指针cur,上一个节点指针pre。然后分三种情况讨论,
pre == NULL || pre->left == cur || pre->right == cur 这种属于traversal down的情况,继续向下遍历即可,临时利用next指针指向下一个节点
cur->left == pre 这种属于刚遍历完左子树,traversal up的情况
cur->right == pre 这种属于刚遍历完右子树,traversal up的情况
6.获得二叉树中序遍历的第k个节点的朴素方法遍历,统计到第k个节点输出即可,时间复杂度O(n)。假如给定的二叉树中每个节点包含其所有子树节点数量和,如何优化寻找第k个节点的算法。时间复杂度可以优化至O(h),h为树的高度。
其实题目思路比较容易获得,快速的缩减问题规模就可以了。查看当前节点的左子树的数量,
如果当前节点左子树的数量等于k,则可知当前节点为查找所需的节点。如果左子树的节点数量大于或等于k,则可以将问题缩小到寻找左子树的第k个节点。
如果当前节点左子树的数量小于k-1 ,则可知第k个节点在右子树中,寻找右子树中第k-(左子树节点数量+1)即可。
7.根据中序遍历和后序或者先序遍历还原二叉树。
leetcode中的题目,思路比较简单,后序/先序可以先确定根节点,根据根节点去分割中序遍历,递归调用左子树和右子树即可。
另外先序和后序无法唯一还原出二叉树,所以这种题目一般就是中序匹配另外一个遍历序。
扩展问题:根据给定的一个数组A,构造max树:max树定义是根节点为A数组中最大值,假设最大值的坐标为m,则左子树右A[0:m-1]构成,右子树由A[m+1,n]构成,递归的利用最大值构造左子树,右子树。设计高效的构造max树的方法。
比较直观的方法每次寻找最大值即可,这样每寻找最大值的时间复杂度为O(n),所以总的时间复杂度为O(n^2)。如果想要优化必须考虑从最大值获取的角度优化。可以分别从左至右,从右至左保存最大值。或者利用单调队列借助栈的功能完成预处理。
8.如果给定一个包含NULL节点的先序遍历结果,能够O(n)还原出二叉树吗?后序和中序呢?
这里借助栈即可,先序和后序,不断的从栈中弹出两个节点与当前节点构成小树压入栈。最后为一个完整的二叉树。
中序的遍历无法唯一还原出二叉树。因为所有树形的遍历结果序列均相同。
可以思考下包含NULL的层序遍历二叉树(也很简单)。
9.将二叉树的所有子节点连接成链表。
递归,然后判断是否子节点,如果子节点连接一下。保存一个全局的头结点变量即可。
10.设计一个输出二叉树外围节点的方法。外围节点的解释:下图需要输出的序列A,B,D,G,J,K,L,M,N,I,F,C

前一个题目已经完成了叶子节点的链表化了,输出也不是困难的事情,所以这个题目的难点在于输出左边外围和右边外围。
刚开始思考能否利用Morris遍历输出外围节点,后来画一个非完全二叉树之后发现挺复杂的。
答案的思路非常的简洁,左边外围节点的特点是如果当前节点外围节点,则该节点的左节点为外围节点,若左节点为空,则该节点的右子节点为外围节点。
右边外围节点的特点是如果当前节点外围节点,则该节点的右节点为外围节点,若右节点为空,则该节点的左子节点为外围节点。
注意,左边外围和右边外围节点的输出顺序,不同。右边可参考逆序输出链表,递归实现相当简洁。
11.求二叉树中两个节点最近公共组先的方法。
思路比较类似第一个题目的思路,递归,但是需要传递两个参数(或者最近公共祖先利用全局变量)
a.如果两个节点均在左子树,则递归左子树寻找最近公共祖先。
b.如果两个节点分别在左右子树,则当前节点返回。
c.如果当前节点为其中一个节点,则返回当前节点。
(这个算法从来没有coding过,需要练习一下,算是基础的操作)
12.如果二叉树中包含parent指针,可以优化二叉树中求两个节点最近公共祖先的方法吗?
有了parent指针,这样就可以同时从给定的两个节点向上找最先交叉的节点的,所以问题转换为两个单链表找最先出现交叉的节点。
a.方法是三遍扫描,首先针对每个节点,从当前节点统计至末尾节点,分别统计出两个链表的长度,然后长度较大的先走动长度之差的距离,然后两个指针同时走动,第一次汇合的地方就是最近的公共祖先。
b.如果使用上述的方法,时间复杂度为最深节点的深度。因为需要统计长度。然后后来该问题继续深入问了一下能够进一步优化时间复杂度。
当时想想确实没有办法进一步优化时间复杂度了,思路被阻塞了。完全没想到空间换时间的策略,题目没要求空间复杂度,就考虑一下牺牲空间。
策略是利用hash表,每次遍历两个节点,然后添加至hash表。同时向前推进,如果遍历的节点已经出现在hash表,表示该节点是第一次汇合的节点。(空间换取时间)
13.给定一个字符串S和一系列字符串集合D,找到S中最短的字符串前缀,满足该前缀不是D集合中任意一个字符串的前缀。
求最短公共前缀的方法是用Trie树,这里也需要使用Trie树的方法。(针对字符串,trie树的效率高于hash,fb的面试失败就是没有第一时间想到这个概念,用的不熟练)
Trie树字母表示在边的扩展中,节点一般存储true或者false代表是否到达单词,或者存储vector<string>容器代表该路径可达的所有单词,依据题目来决定Trie树的结构。
(需要练习一下)
二叉树的基础题目学习(EPI)的更多相关文章
- 数组和字符串的基础题目学习(EPI)
学习的速度有些慢,脑袋转动的频率有些不是很高.不过今天的效率我觉得还是可以,应该不能称效率吧,就是整个感觉不错,感觉自己补充了很多的知识.其实G家和F家败了之后不知道看看算法题对接下来的找工作帮助是否 ...
- 堆的基础题目学习(EPI)
堆的应用范围也比较广泛,经常游走在各种面试题目之前,不论算法设计的题目还是海量数据处理的题目,经常能看到这种数据结构的身影.堆其实就是一个完全二叉树的结构,经常利用数组来实现.包含最大堆和最小堆两种. ...
- 链表的基础题目学习(EPI)
链表的题目总体来说细节比较多,因为链表的题目在操作链表的过程中本身有些复杂,所以如果链表作为编程题出现的时候,多数情况下题目本身的思路可能不是很复杂,不要把题目往复杂的方向去思考就好了~这里的链表只是 ...
- python基础练习题(题目 学习使用auto定义变量的用法)
day28 --------------------------------------------------------------- 实例042:变量作用域 题目 学习使用auto定义变量的用法 ...
- iOS 面试基础题目
转载: iOS 面试基础题目 题目来自博客:面试百度的记录,有些问题我能回答一下,不能回答的或有更好的回答我放个相关链接供参考. 1面 Objective C runtime library:Obje ...
- 20145308 《网络对抗》Web安全基础实践 学习总结
20145308 <网络对抗> Web安全基础实践 学习总结 实验内容 本实践的目标理解常用网络攻击技术的基本原理.Webgoat实践下相关实验. 基础问题回答 (1)SQL注入攻击原理, ...
- [pwn基础]Pwntools学习
目录 [pwn基础]Pwntools学习 Pwntools介绍 Pwntools安装 Pwntools常用模块和函数 pwnlib.tubes模块学习 tubes.process pwnlib.con ...
- 零基础如何学习java更有效呢?
零基础学java,不知道该如何入手?也不知道学习的方向,很多人会问零基础怎么样学习,有没有什么入门的书籍推荐:只要方法正确,零基础学好java也是有机会的哦. 一.理解Java思想 Java是一门面向 ...
- Swift基础语法学习总结(转)
Swift基础语法学习总结 1.基础 1.1) swift还是使用// 和/* */ 来注释,并且/* */允许多行注释. 1.2) swift使用print和println打印,它的传参是一个泛型 ...
随机推荐
- R12.1.3 & R12.2.X 注册客户化应用
R12.2 官方出了运行补丁脚本就可以自动创建客户化应用,所以也把此补丁应用在 R12.1.3上验证一下其可行性,做出以下实验. 1.创建客户化应用账号CUX --login user system ...
- Launch 启动全屏 隐藏上方状态栏
1:statusBar字体为白色 在plist里面设置View controller-based status bar appearance 为 NO:设置statusBarStyle 为 UISta ...
- log4net.Layout.PatternLayout 用 conversion 模式格式化日志事件【翻译】
原文地址 log4net.Layout.PatternLayout,是一个灵活的布局,配置模式字符串. 线程安全.该类型的 Public static 成员对多线程操作是安全的.实例成员不保证线程安全 ...
- oracle排序后的第一条记录
该查寻语句没有经过任何的优化,因为oracle没有SQL的TOP关键字,但是有一个ROWNUM的列,因此,可以通过ROWNUM来进行查询.oracle的关于rownum的参考手册里面提到了 分析 ...
- 如果你喜欢python,那你迟早会喜欢上julia的!
你可曾想过有那么一门语言: 这门语言能够有C语言一样的速度,Ruby一样得活力(dynamism).像homoiconic一样的语言,它像Lisp一样有宏,但是也像Matlab一样有显而易见.熟悉的数 ...
- jQuery动态添加删除与添加表行代码
具体实现代码如下: table的HTML如下: 代码如下 复制代码 <input type="button" value="添加一行" />< ...
- 如何在servlet刚启动时候获取服务器根目录?
public class InitServlet extends HttpServlet{ public static String root; @Override public void init( ...
- 菜鸟教程之工具使用(六)——让Maven项目直接在eclipse内部的Tomcat中运行
Hello,大家好,好久不见!最近终于安定下来了,可以静下心来写东西了.先写篇简单的,找找感觉.工具系列的本身就比较简单,没什么技术含量.因为说到底,工具只是辅助我们工作的,知道怎么用,然后剩下的就是 ...
- 《转》Babel 入门教程
ECMAScript 6是JavaScript语言的下一代标准,已经在2015年6月正式发布了.Mozilla公司将在这个标准的基础上,推出JavaScript 2.0.ES6的目标,是使得JavaS ...
- post请求数据量过大,提交失败
HttpRuntimeSection.MaxRequestLength 属性,请求的最大大小(以千字节为单位). 默认大小为 4096 KB (4 MB) <system.web> < ...