LeetCode中二叉树题目总结
本文仅为博主个人总结,水平有限,欢迎大神指出不妥处。
关于二叉树的相关概念可以参见二叉树的百度百科,或binary tree Wiki。
二叉树结点类的常见定义为:
/* Definition for a binary tree node. */
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
提到二叉树,首先要提到二叉树的四种遍历方式:前序遍历、中序遍历、后续遍历和层次遍历,其中前三种为一类,一般是使用栈(stack)实现,三种遍历方式的区别在于访问根结点的顺序不同;最后一种一般使用队列(queue)实现。这四种遍历是很多题目的基础,要弄懂。
一、前序遍历、中序遍历、后续遍历
1、前序遍历:访问顺序是根结点->左孩子->右孩子。迭代算法实现的主要思想为:先访问根结点,然后若右孩子存在就将其存入栈中,若左孩子存在,则根结点沿左孩子一直到叶结点同时依次访问;到了叶结点时, 去除栈顶结点继续访问,直到栈为空。Binary tree preorder traversal。
2、中序遍历:访问顺序是左孩子->根结点->右结点。迭代算法实现的主要思想为:因为先访问左孩子(从身为叶结点的左孩子开始),所以可以利用栈先进后出的特点,我们先沿着左孩子一直将结点存入栈中,到叶结点时,从栈中取出结点开始访问,然后取当前结点的右孩子接着进行循环,直到root为NULL且栈为空。Binary tree inorder traversal。
3、后序遍历:访问顺序是左孩子->右孩子->根结点。迭代算法实现的主要思想为:最重要的是定义一个指针记录下前一个访问过的,这样可以避免重复访问。有两种思路:一、按照后序遍历访问结点的顺序,将右、左孩子入栈(注意入栈顺序),若到达根结点或当前结点的左、右孩子中已被访问过,则从栈中取出结点访问。二、可以从中序遍历的基础上改进,即不断将左孩子压入栈中,然后若当前结点的右孩子没有被访问过,则转向遍历以当前右孩子为根结点的树,若访问过,则取出栈顶元素访问即可。这两种思路中都要注意对前指针的更新。Binary tree postorder traversal。
二、层次遍历
1、一般是:利用队列先进先出的特点,依次将结点的左、右孩子入队,然后依次出队访问,以此为循环。LeetCode中有关这点为Binary tree level order traversal,不过题中要求按行输出每一行结点的值。这里的关键问题是如何分层。迭代算法的实现有三种:一、定义两个计数器:一个记录本层结点数,一个记录下当前层下一层的结点数,这样遍历完一层后输出,然后转向下一层,并更新结点数。二、只需一个计数器,记录下当前行结点数,使用两层while循环结构,每访问完一个结点,计数器减1,直到该层中所有结点访问;然后访问下一行,并通过size()得到该行的结点数,以此进行循环。三、在每一层的最后向栈中压入NULL当作该行的结束符,这样出队时,每遇到NULL时,就保存这一行中的结点,值得注意的时,只有队列不为空时才压入NULL。
2、题Binary tree level order traversal ii是上一题的延续,变化在于结果的输出:从下到上按行输出每行的结点值。有两种方法,一、用上一题的结果,只是到最后,将最后的结果反转就行;二、主体还是和上一题一样,只是以行为单位保存每行结点时,先存入栈中,利用其先进后出的特点完成反转输出。
3,、题Binary tree Zigzag level order traversal可以说是二叉树层次遍历的延续。我们只要在以行为单位将每行结点值存入最终结果时,遇到偶数行时,将该行的结点值反转以后存入最后结果即可。
4、题Maximum depth of binary tree和The minimum depth of binary tree的迭代法可以看成是层次遍历的延续,求最大深度,到最底层即可,最小深度遇到第一个叶结点所在层即可。对于这两题的递归解法,关键在于理解二叉树深度这一概念。
三、使用前序遍历、中序遍历、后续遍历中的两种构建二叉树
根据三种遍历结点的顺序,我们可以得到只有前序遍历+中序遍历、中序遍历+后续遍历才能实现二叉树的构造,而前序遍历+后续遍历是不能构建二叉树的,因为,没法通过根结点的位置将左右子树分开。这两种方式构造二叉树的思路相同,都是先根据根结点确定左右子树,然后依次找到以每个结点的左右子树,递归实现构造二叉树,值得注意的,下标问题。Construct binary tree from preorder and inorder travesal、Construct binary tree from inorder and postorder travesal。
四、求和问题
1、题Sum root to leaf numbers,求得是根结点到所有叶结点所形成的数(根结点为最高位)的和。Binary tree maximum path sum 中起始节点可以是任意节点。Path Sum给定一个数,判断二叉树中是否存在从根到叶节点,使路径上所有结点值的和等于给定值。第一题和第三题可看成是一个递归实现的一个逆过程。这几题的关键在于理解题意(特别是第二题)以后,使用递归调用解题。当然第三题可以利用后续遍历的思想实现迭代解题。
2、题Path Sum II是题Path Sum的延续,本题中要输出所有符合题意的路径。迭代解法也是可以通过后续遍历的思想解决。这里分为将这两题分开说的原因,主要是在Path Sum II的递归解法上。这题的递归解法在后面很多题中都可以得到体现,值得注意。
五、填充问题
题Populating next right pointer in each node和Populating next right pointer in each node ii是一个类型的,一般解法是利用层次遍历的思想,使用队列,来实现层与层之间的转换。在要求不能使用额外空间时,我们可以利用其提供的next指针来实现。第一题中涉及到的几个二叉树的概念可见博友veli的博客。两题的主要思路是,先保存当前行的下一行中最左端的结点以便于实现层层之间转换。至于第二题中要注意的是要定义一个指针,实现层内的穿针引线。参考递归实现可以明白整个算法的结构。
六、一般二叉树的特殊情况
题Same tree和Symmetric tree是一般二叉树的特殊情况。第一题判断是否为相同二叉树,可以使用两队列,按照层次遍历的方式,两二叉树的左右孩子的入队顺序相同,判断各种情况下是否符合;第二题判断树是否为对称二叉树,首先要理解对称的概念,是从整体上的对称,也可以使用两个队列实现判断,不过要注意的是入队的顺序。也可以使用一个栈,入栈顺序是,先左左,右右,然后左右,右左,对应的入栈,只需比较栈顶连续两结点是否相等即可。
七、搜索二叉树
首先要明白搜索二叉树的概念,针对一棵二叉树是否为搜索二叉树有题Validate binary search tree,要紧紧的围绕搜索二叉树的中序遍历是非降序列来解题。有几种方法:一、定义一个指针指向当前结点的前一个结点,利用二叉树中序遍历的思路,将两者的值进行比较,只要前者大于后者就不是搜索二叉树;二、可以将利用中序遍历将二叉树结点值都存入一个数组中,然后遍历数组看是否为非降序型。
题Unique binary search trees给定数列,判断能构成几种不同的二叉搜索树。关键在弄明白给定数和搜索二叉树种类的关系(卡特兰数)。然后依次可以写出动态规划或递归的解法。Unique binary search trees ii和Path Sum II的递归解法都是类似的,要深刻体会。
题Recover binary search tree关键在找到出错的地方,有两种方式,一:可以将结点的值存入数组中,然后排序以后,将值依次赋给对应节点;二:使用中序遍历,找到出错的点,然后交换即可。
其他
Balanced binary tree,这题关键在理解平衡二叉树的概念:任何结点为根结点的左、右子树的深度差不超过1(最大深度差)。
二叉树中两个结点最近的公共祖先汇总中讲解了搜索二叉树、一般二叉树带指向父结点的指针和一般二叉树的最近公共祖先。三者依次,利用二叉搜索树的根结点大于左孩子小于右孩子的特点;将二叉树转变为链表类型;当给定两结点值在某一节点的左右子树中时,为最近的公共祖先的思想。
LeetCode中二叉树题目总结的更多相关文章
- leetcode - 位运算题目汇总(下)
接上文leetcode - 位运算题目汇总(上),继续来切leetcode中Bit Manipulation下的题目. Bitwise AND of Numbers Range 给出一个范围,[m, ...
- leetcode top 100 题目汇总
首先表达我对leetcode网站的感谢,与高校的OJ系统相比,leetcode上面的题目更贴近工作的需要,而且支持的语言广泛.对于一些比较困难的题目,可以从讨论区中学习别人的思路,这一点很方便. 经过 ...
- c++中二叉树的先序中序后序遍历
c++中二叉树的先(前)序.中序.后序遍历 讲解版 首先先看一个遍历的定义(源自度娘): 所谓遍历(Traversal),是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问.访问结点所做的 ...
- leetcode tree相关题目总结
leetcode tree相关题目小结 所使用的方法不外乎递归,DFS,BFS. 1. 题100 Same Tree Given two binary trees, write a function ...
- [LeetCode] 二叉树相关题目(不完全)
最近在做LeetCode上面有关二叉树的题目,这篇博客仅用来记录这些题目的代码. 二叉树的题目,一般都是利用递归来解决的,因此这一类题目对理解递归很有帮助. 1.Symmetric Tree(http ...
- [LeetCode] 动态规划入门题目
最近接触了动态规划这个厉害的方法,还在慢慢地试着去了解这种思想,因此就在LeetCode上面找了几道比较简单的题目练了练手. 首先,动态规划是什么呢?很多人认为把它称作一种"算法" ...
- 关于LeetCode上链表题目的一些trick
最近在刷leetcode上关于链表的一些高频题,在写代码的过程中总结了链表的一些解题技巧和常见题型. 结点的删除 指定链表中的某个结点,将其从链表中删除. 由于在链表中删除某个结点需要找到该结点的前一 ...
- LeetCode - 排列相关题目
1.获取全排列 https://leetcode.com/problems/permutations/submissions/ 按字典序输出: 这里用的是vector<int>,不是引用. ...
- All LeetCode Questions List 题目汇总
All LeetCode Questions List(Part of Answers, still updating) 题目汇总及部分答案(持续更新中) Leetcode problems clas ...
随机推荐
- android学习十三 首选项
1,首选项可用用来持久保存用户设置,游戏最高分等 2,首选项有,列表首选项,复选框首选项,对话框首选项.. 3,通过xml文件和代码创建首选项 addPreferencesFromResou ...
- 【廖雪峰老师python教程】——IO编程
同步IO 异步IO 最常见的IO——读写文件 读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一 ...
- MySQL☞sign函数
sign( )函数:判断数值的正负性,如果数值是正数,返回值是1,如果该数值是负数,返回值是-1,如果该数值是 0,返回值也是0. 格式: select sign(数值) from 表名 例子: 1. ...
- unity中虚拟摇杆的实现
实现效果: 实现: 使用NGUI添加虚拟摇杆背景和其子物体按钮,为按钮Attach boxcollider和ButtionScript.为按钮添加如下脚本: 注意:其中的静态属性可以在控制物体移动的 ...
- TCP/IP协议的学习笔记
1.OSI和TCP/IP的协议体系结构 OSI是开放系统互连参考模型,它的七层体系结构概念清楚,理论也比较完整,但它既复杂又不实用.而TCP/IP是一个四层的体系结构,它包含应用层.传输层.网际层和网 ...
- Linux文件系统简介和软链接和硬链接的区别
Linux有着极其丰富的文件系统,大体可分为如下几类: 网络文件系统:如nfs.cifs等: 磁盘文件系统:如ext3.ext4等: 特殊文件系统:如prco.sysfs.ramfs.tmpfs等: ...
- python常用命令—终端安装win32的两种方法
1, pip install pywin32 2, pip install pypiwin32
- [Install] TeamViewer
安装TeamViwer 1. $ sudo apt-get -f install 2. 使用gdebi安装TeamViwer. 所以先安装gdebi package. $ sudo apt-get i ...
- Elasticsearch 排序插件的开发
直接观察到的几个问题 简单expression脚本的执行效率 > java 插件,10000条数据可以测试出1ms左右的差距. Es会不断调用newScript来创建"足够多" ...
- Alpha版——版本控制报告(Thunder)
Part One 回答问题: 0.在吹牛之前,先回答这个问题:如果你的团队来了一个新队员,有一台全新的机器,你们是否有一个文档,只要设置了相应的权限,她就可以根据文档,从头开始搭建环境,并成功地把最新 ...