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 ...
随机推荐
- php常用几个数组的区别
本文主要介绍的php数组函数主要有:sort.rsort.asort.arsort.ksort.krsort 测试数据定义一个关联数组如下: $data=[ 'f'=>123, 'b'=> ...
- webservice调用天气
class WebServiceHelper { /// <summary> /// 动态调用WebService /// </summary> /// <param n ...
- 使用maven构建web项目(简易版)
在eclipse中使用maven开发一个web项目 第一步:安装maven:在Windows上安装Maven 中间省略很多步骤....(包括关于eclipse中配置maven) 第二步:不用懂任何ma ...
- Idea Live Templates
常用live templates 模板 注释 : * * @param $params$ * @return $return$ * $date$ $time$ chiyuanzhen743 */ lo ...
- Laxcus大数据管理系统2.0(7)- 第五章 数据构建
第五章 数据构建 在数据处理过程,我们经常会遇到这样的情况:大多数时候,用户最初输入的数据会含有大量无意义的.杂乱的信息,需要经过提炼.收集.汇总等一系列手段,才能产生有意义和用户可识别的数据内容:当 ...
- Machine Learning笔记整理 ------ (五)决策树、随机森林
1. 决策树 一般的,一棵决策树包含一个根结点.若干内部结点和若干叶子结点,叶子节点对应决策结果,其他每个结点对应一个属性测试,每个结点包含的样本集合根据属性测试结果被划分到子结点中,而根结点包含样本 ...
- Python3 数据类型-元组
Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号,列表使用方括号. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可. 实例1(Python3.0+): tu ...
- 关于set和get机制的整理
首先这是es5新增的:定义是设置和获取对象属性时候出发的方法,属于修饰器: 犀牛书例子: function test(n){ return { get count(){ return n }, set ...
- Java学习个人备忘录之异常
概述 异常:是在运行时期发生的不正常情况. 在java中用类的形式对不正常情况进行了描述和封装对象. 描述不正常的情况的类,就称为异常类. 以前正常流程代码和问题处理代码相结合,现在将正常流程代码和问 ...
- 《软件工程实践》第五次作业-WordCount进阶需求 (结对第二次)
在文章开头给出结对同学的博客链接.本作业博客的链接.你所Fork的同名仓库的Github项目地址 本作业博客链接 github pair c 031602136魏璐炜博客 031602139徐明盛博客 ...