有读者反馈,现在谁不是为了找工作才学的数据结构,确实很有道理,是我肤浅了。所以为了满足大家的需求,这里总结下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里的二叉树的更多相关文章

  1. LeetCode:翻转二叉树【226】

    LeetCode:翻转二叉树[226] 题目描述 翻转一棵二叉树. 示例: 输入: 4 / \ 2 7 / \ / \ 1 3 6 9 输出: 4 / \ 7 2 / \ / \ 9 6 3 1 题目 ...

  2. 【Leetcode】104. 二叉树的最大深度

    题目 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说明: 叶子节点是指没有子节点的节点. 示例:给定二叉树 [3,9,20,null,null,15,7 ...

  3. Leetcode 331.验证二叉树的前序序列化

    验证二叉树的前序序列化 序列化二叉树的一种方法是使用前序遍历.当我们遇到一个非空节点时,我们可以记录下这个节点的值.如果它是一个空节点,我们可以使用一个标记值记录,例如#. 例如,上面的二叉树可以被序 ...

  4. Java实现 LeetCode 331 验证二叉树的前序序列化

    331. 验证二叉树的前序序列化 序列化二叉树的一种方法是使用前序遍历.当我们遇到一个非空节点时,我们可以记录下这个节点的值.如果它是一个空节点,我们可以使用一个标记值记录,例如 #. _9_ / \ ...

  5. 【algo&ds】【吐血整理】4.树和二叉树、完全二叉树、满二叉树、二叉查找树、平衡二叉树、堆、哈夫曼树、B树、字典树、红黑树、跳表、散列表

    本博客内容耗时4天整理,如果需要转载,请注明出处,谢谢. 1.树 1.1树的定义 在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结 ...

  6. 遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化

    遍历二叉树   traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化 1. 二叉树3个基本单元组成:根节点.左子树.右子树 以L.D.R ...

  7. javascript实现数据结构: 树和二叉树的应用--最优二叉树(赫夫曼树),回溯法与树的遍历--求集合幂集及八皇后问题

    赫夫曼树及其应用 赫夫曼(Huffman)树又称最优树,是一类带权路径长度最短的树,有着广泛的应用. 最优二叉树(Huffman树) 1 基本概念 ① 结点路径:从树中一个结点到另一个结点的之间的分支 ...

  8. [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 ...

  9. 【LeetCode题解】二叉树的遍历

    我准备开始一个新系列[LeetCode题解],用来记录刷LeetCode题,顺便复习一下数据结构与算法. 1. 二叉树 二叉树(binary tree)是一种极为普遍的数据结构,树的每一个节点最多只有 ...

随机推荐

  1. Solution -「SP 6779」GSS7

    \(\mathcal{Description}\)   给定一棵 \(n\) 个点的带点权树,\(q\) 次操作: 路径点权赋值. 询问路径最大子段和(可以为空).   \(n,q\le10^5\). ...

  2. kubeasz 部署高可用 kubernetes 集群

    文章目录 环境准备 配置模板机 配置hosts解析 配置ssh 免密钥登陆 kubeasz 部署服务准备 配置主机清单 部署集群 环境准备 IP HOSTNAME SYSTEM 192.168.131 ...

  3. 依赖于angular的table组件

    组件实现了以下功能 1. 列宽可动态拖动 2. 列数据排序 3. 列过滤 4. 列位置自由调整 除了需要引入angular.js(我用的是1.4.6版本),还需要引用一个angular衍生出来的插件n ...

  4. 关于WebStorm 破解

    建议资金宽裕,支持正版 2017.2.27更新 选择"license server" 输入:http://idea.imsxm.com/ 2016.2.2 版本的破解方式: 安装以 ...

  5. 用实例带你深入理解Java内存模型

    摘要:本文的目的来理解 J V M 与我们的内存两者之间是如何协调工作的. 本文分享自华为云社区<一文带你图解Java内存模型>,作者: 龙哥手记 . 我们今天要特别重点讲的,也就是我们本 ...

  6. 八大排序算法之直接插入排序(InsertionSort)

    常见的排序算法 今天复习[直接插入排序] 核心思想:有序数组中 找位置 -- 给无序数组第一个 找位置 ` public class InsertionSort { // 核心思想:有序数组中 找位置 ...

  7. jQuery下载安装使用教程

    一:下载jQuery 下载链接:jQuery官网 中文文档:jQuery AP中文文档 1.jQuery版本 1.x:兼容IE678,使用最为广泛的,官方只做BUG维护,功能不再新增.因此一般项目来说 ...

  8. 2021年BI软件系统推荐,知名商业智能厂商品牌

    国内外一直有一些厉害的商业智能厂商,在国外,例如国外微软的PowerBI.在国外是商业智能的行业领导者,在国外的市场占有率上远远领先其它产品,然而在中国市场却落后于国内商业智能厂商思迈特软件的Smar ...

  9. Android编译优化系列-kapt篇

    作者:字节跳动终端技术---王龙海 封光 兰军健 一.背景 本文是编译优化系列文章之 kapt 优化篇,后续还会有 build cache, kotlin, dex 优化等文章,敬请期待.本文由Cli ...

  10. linux中docker容器安装vi命令详解

    在使用docker容器时,同时你docker里的系统正好是debian或ubuntu的时候,有时候里边没有安装vim,敲vim命令时提示说:vim: command not found,这个时候就需要 ...