5分钟了解二叉树之LeetCode里的二叉树
有读者反馈,现在谁不是为了找工作才学的数据结构,确实很有道理,是我肤浅了。所以为了满足大家的需求,这里总结下LeetCode里的数据结构。对于我们这种职场老人来说,刷LeetCode会遇到个很尴尬的问题,就是每道题看起来都很熟悉,都觉得是十拿九稳了,但是真要你写出来,又很容易卡壳。如果人家让你写个反转链表的题目都能卡壳,那场面就会相当尴尬了。起初我还是对刷题比较抗拒的,感觉就跟学习交通法规一样,你花个半天时间就能背下来,就能考个九十多分,靠这个来面试实在是太low了。现在也释然了,一方面是现在人才太多了,企业已经没法通过面试来筛选人才,所以选择算法来做一层保底的筛选,如果你不会,就算你有多牛,也只能归类到垃圾的队伍了,所以这事得顺应时势,适者生存;另一方面比如字节这种公司确实对算法需求比较强,人家考核算法也是实际需要,也没必要觉得他是在有意刁难。
LeetCode题型
LeetCode应该怎么刷呢,首先很重要的一点是要多花时间,每天刷一两道题,保持好做题的感觉。这玩意熟能生巧,经常练习有助于治疗老年痴呆。另外我在网络收集了一些网友刷LeetCode的经验,对于初刷LeetCode的同学比较有用:
- 按分类刷;每个分类从 Easy 到 Medium 顺序刷;
- 优先刷 树、链表、二分查找、DFS、BFS 等面试常考类型;
- 优先刷题号靠前的题目;
- 优先刷点赞较多的题目;
本文主要是讲LeetCode中的数据结构以及考点,方便大家加深认识。这次我们首先讲的是LeetCode里的树。为什么先讲树呢,因为树是我们用的最多,实用性最强,也最容易在面试中被问到的一种数据结构,小到我们编程语言里的map,大到mysql的索引,都离不开树这个数据结构。可以这样说,你把树搞明白了,至少能应付一半的面试了。
在LeetCode的标签分类题库中,和树有关的标签有:树(227)、二叉树(198)、二叉搜索树(54)、字典树(49)、线段树(28)、树状数组(20)、最小生成树(5)。这些题中,二叉树又是树中的重点,可以归纳为:
上图主要是归纳了一些LeetCode常见题型和概念,方便大家记忆和查漏补缺。其中打星的是其中比较难的部分,不过这东西见仁见智,也许有些人也会觉得很简单。
下面帮大家回忆一下关于二叉树的基础概念。
树
要理解什么是二叉树,首先需要理解什么是树( tree )。可以使用递归的方式定义树:
一棵树是一些节点( node )的集合。这个集合可以是空集,说不是空集,则树由称作根( root )的节点 r 以及0个或多个非空的(子)树T1, T2, ..., Tk组成,这些子树中每一棵都被来自根r的一条有向的边( edge )所连接。
每一棵子树的根叫作根 r 的儿子 (child), 而 r 是每一棵子树的根的父亲 ( parent )。下图展示了用递归定义的典型的树:
在下面的树中,节点A是根。节点F有一个父亲A并且有儿子K、L和M。每一个节点可以有任意多个儿子,也可能是是零个儿子。没有儿子的节点称为树叶( leaf ),图中的树叶是B、C、H、I、P、Q、K、L、M和N。具有相同父亲的节点为兄弟 ( siblings )。因此,K、L和M都是兄弟。用类似的方法可以定义祖父( grandparent )和孙子( grandchild )关系。
从节点 n1 到 nk 的路径( path )定义为节点n1, n2, ..., nk的一个序列,是的对于 1 <= i < k 的节点ni是ni+1的父亲,这条路径的长( length ) 是该路径上的边的条数,即 k-1。从每一个节点到他自己有一条长为0的路径。注意,在一棵树中从根到每个节点恰好存在一条路径。
对于任意节点ni,ni 的深度( depth ) 为从根到 ni 的唯一路径的长。因此,根的深度为 0。节点 ni 的高( height )是从ni到一片树叶的最长路径的长。因此所有的树叶的高都是0。一棵树的高度( height of a tree )等于它的根的高。对于图中的树,E的深度为1而高为2;F的深度为1而高也是1;该树的高为3。一棵树的深度( depth of a tree )等于其最深的树叶的深度,该深度总是等于这棵树的高。
如果存在从n1到n2的一条路径,那么n1是n2的一位祖先( ancestor ),而n2是n1的一个后裔( descendant )。如果n1 != n2,那么n1是n2的真祖先(proper ancestor),而n2是n1的真后裔(proper descendant)。
二叉树
二叉树(Binary tree)是树形结构的一个重要类型,是AVL树,红黑树,二叉堆,大顶堆,小顶堆,多叉树的基础。那么什么是二叉树?下面给出二叉树的递归定义:
二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。
以上图为例,其中 6 是二叉树的根节点,A和B分别是根节点 6 的左子树和右子树;直线相连的节点分别是父节点和子节点,比如 6 是 2 和 8 的父节点,2 和 8 是 6 的子节点;没有子节点的节点叫叶子节点,比如 0、3、5、7、9 、10都是叶子节点。
相关术语
节点(node):包含一个数据元素及若干指向子树分支的信息。上图中的每个圆圈都表示一个节点。
度(degree):一个节点拥有子树的数目称为节点的度 ,叶子的度一定是0。上图中的6、2、8、4的度为2,9的度为1,0、3、5、7、9 、10的度为0。
叶子节点(leaf node):也称为外部节点(external node 或 outer node)、终端节点(terminal node),指没有子树的节点或者度为零的节点。上图中的0、3、5、7、9 、10都是叶子节点。
内部节点(internal node 或 inner node):也称为非终端节点、分支节点(branch node),度不为零的节点称为非终端节点。上图中的6、2、8、4、9都是内部节点。
树的度(degree of tree):树中所有节点的度的最大值。上面的树的度是2,二叉树的度不会超过2。
层(level):节点的层是沿着它和根节点之间的唯一路径的边数。LeetCode中的层是从0开始的,比如上图中的6是第0层,2是第一层。
距离(Distance):沿两个节点之间最短路径的边数。
有序树(Ordered tree):为每个顶点的子节点指定排序的有根树。
森林(Forest):由m(m≥0)棵互不相交的树构成一片森林。如果把一棵非空的树的根节点删除,则该树就变成了一片森林,森林中的树由原来根节点的各棵子树构成。
满二叉树(full binary tree):每个节点都有 0 或 2 个子节点的二叉树。
完全二叉树(complete binary tree):除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。下图所示是一棵完全二叉树:
完美二叉树(perfect binary tree):所有内部节点都有两个孩子并且所有叶子都具有相同深度或相同级别。一棵完美的树总是完全二叉树,但一棵完全二叉树不一定是完美的。
基本操作
递归
针对二叉树的问题的解决中,递归是一种十分常用的编程方式,有必要说明一下。
定义
在数学和计算机科学中,递归指由一种(或多种)简单的基本情况定义的一类对象或方法,并规定其他所有情况都能被还原为其基本情况。
例如,下列为某人祖先的递归定义:
斐波那契数列是典型的递归案例:
- {\displaystyle F_{0}=0}(初始值)
- {\displaystyle F_{1}=1}(初始值)
- 对所有大于1的整数n:{\displaystyle F_{n}=F_{n-1}+F_{n-2}}(递归定义)
一种便于理解的心理模型,是认为递归定义对对象的定义是按照“先前定义的”同类对象来定义的。例如:你怎样才能移动100个箱子?答案:你首先移动一个箱子,并记下它移动到的位置,然后再去解决较小的问题:你怎样才能移动99个箱子?最终,你的问题将变为怎样移动一个箱子,而这时你已经知道该怎么做的。
C++的递归
直接或间接调用自己的函数称为递归函数(recursion function)。一个简单的定义函数的例子是阶乘的计算。数n的阶乘是从1到n的乘积。例如5的阶乘就是120。
1 * 2 * 3 * 4 * 5 = 120
解决这个问题的自然方法就是递归:
int factorial(int val)
{
if (val > 1)
return factorial(val-1)*val;
return 1;
}
递归函数必须定义一个终止条件;否则就会永远递归下去,这意味着函数会一直调用自身知道程序栈耗尽。有时候这种现象称为“无限递归错误”(infinite recursion error)。对于函数factorial,val为1是终止条件。
前序遍历
中序遍历
后序遍历
层序遍历
设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
引用:
https://blog.csdn.net/fuxuemingzhu/article/details/105183554
https://www.cnblogs.com/joelwang/p/10640599.html
https://www.cnblogs.com/liuzhen1995/p/11921771.html
https://leetcode-cn.com/circle/discuss/J8XFse/
https://baike.baidu.com/item/%E4%BA%8C%E5%8F%89%E6%A0%91/1602879
https://www.jianshu.com/p/c5d48937f2d9
https://en.wikipedia.org/wiki/Binary_tree
https://en.wikipedia.org/wiki/Tree_(data_structure)
https://zh.wikipedia.org/wiki/%E9%80%92%E5%BD%92
《C++ Primer 中文版》第4版
https://baike.baidu.com/item/%E4%BA%8C%E5%8F%89%E6%A0%91%E9%81%8D%E5%8E%86/9796049?fr=aladdin
5分钟了解二叉树之LeetCode里的二叉树的更多相关文章
- LeetCode:翻转二叉树【226】
LeetCode:翻转二叉树[226] 题目描述 翻转一棵二叉树. 示例: 输入: 4 / \ 2 7 / \ / \ 1 3 6 9 输出: 4 / \ 7 2 / \ / \ 9 6 3 1 题目 ...
- 【Leetcode】104. 二叉树的最大深度
题目 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说明: 叶子节点是指没有子节点的节点. 示例:给定二叉树 [3,9,20,null,null,15,7 ...
- Leetcode 331.验证二叉树的前序序列化
验证二叉树的前序序列化 序列化二叉树的一种方法是使用前序遍历.当我们遇到一个非空节点时,我们可以记录下这个节点的值.如果它是一个空节点,我们可以使用一个标记值记录,例如#. 例如,上面的二叉树可以被序 ...
- Java实现 LeetCode 331 验证二叉树的前序序列化
331. 验证二叉树的前序序列化 序列化二叉树的一种方法是使用前序遍历.当我们遇到一个非空节点时,我们可以记录下这个节点的值.如果它是一个空节点,我们可以使用一个标记值记录,例如 #. _9_ / \ ...
- 【algo&ds】【吐血整理】4.树和二叉树、完全二叉树、满二叉树、二叉查找树、平衡二叉树、堆、哈夫曼树、B树、字典树、红黑树、跳表、散列表
本博客内容耗时4天整理,如果需要转载,请注明出处,谢谢. 1.树 1.1树的定义 在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结 ...
- 遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化
遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化 1. 二叉树3个基本单元组成:根节点.左子树.右子树 以L.D.R ...
- javascript实现数据结构: 树和二叉树的应用--最优二叉树(赫夫曼树),回溯法与树的遍历--求集合幂集及八皇后问题
赫夫曼树及其应用 赫夫曼(Huffman)树又称最优树,是一类带权路径长度最短的树,有着广泛的应用. 最优二叉树(Huffman树) 1 基本概念 ① 结点路径:从树中一个结点到另一个结点的之间的分支 ...
- [LeetCode] Path Sum 二叉树的路径和
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all ...
- 【LeetCode题解】二叉树的遍历
我准备开始一个新系列[LeetCode题解],用来记录刷LeetCode题,顺便复习一下数据结构与算法. 1. 二叉树 二叉树(binary tree)是一种极为普遍的数据结构,树的每一个节点最多只有 ...
随机推荐
- pytest(9)-标记用例(指定执行、跳过用例、预期失败)
pytest中提供的mark模块,可以实现很多功能,如: 标记用例,即打标签 skip.skipif标记跳过,skip跳过当前用例,skipif符合情况则跳过当前用例 xfail标记为预期失败 标记用 ...
- CentOS 7 编译部署LAMP环境
文章目录 1.需求以及环境准备 1.1.版本需求 1.2.环境准备 1.3.安装包准备 2.编译升级Openssl 2.1.查看当前Openssl版本 2.2.备份当前版本Openssl文件 2.3. ...
- MacBook Pro 新手入门
Mac从拆箱到入门 记录首次使用Mac的我的历程,不是专业的Mac使用教程,只是简单的记录.还有我在使用过程中一些用到的功能都一些小提示吧. 1.首次开机配置,对于一个完全的新手来说(也就是我) ...
- 【Kotlin】初识Kotlin(二)
[Kotlin]初识Kotlin(二) 1.Kotlin的流程控制 流程控制是一门语言中最重要的部分之一,从最经典的if...else...,到之后的switch,再到循环控制的for循环和while ...
- 使用ensp模拟器中的防火墙(USG6000V)配置NAT(网页版)
使用ensp模拟器中的防火墙(USG6000V)配置NAT(网页版)一.NAT介绍NAT(Network Address Translation,网络地址转换):简单来说就是将内部私有地址转换成公网地 ...
- 中国著名hacker---陈三堰
在学习<网络攻防>这门课程中,我了解到了黑客之间的斗智斗勇,同样也对中国本土黑客产生了兴趣,之后,我将用一段时间扒一扒这其中比较有分量的传奇人物--陈三堰. 真名:陈三堰 网名:陈三少 所 ...
- mac上Navicat新建数据库3680错误解决办法
mac上Navicat新建数据库3680错误解决办法 1.在设置里关闭mysql,若不能关闭,在终端输入: sudo /usr/local/mysql/support-files/mysql.serv ...
- 【C#IO 操作】stream 字节流|字符流 |比特流
stream的简介 Stream 所有流的抽象基类. 流是字节序列的抽象,例如文件.输入/输出设备.进程中通信管道或 TCP/IP 套接字. Stream类及其派生类提供这些不同类型的输入和输出的一般 ...
- 工程师计划1-> 项目管理1 | 项目与项目管理
这学期报了一门课,项目管理,是一门网课,但跟之前不一样,我期待能够从这门课中学到一些东西.这是我上学期在组织毛概小组大作业时遇到困难时,意识到自己应该学习这门课. 工程师计划其实是一直以来想要把学习的 ...
- Typora简单使用
Typora介绍 Typora是一款轻量级的Markdown编辑器,它没有采用传统编辑器那样源代码和预览双栏显示的方式,让你所见即所得,能够及时预览.目前Typora在IT领域的人气极高,这也致使原来 ...