Skip to content

Commit

Permalink
“颗” -> “棵”
Browse files Browse the repository at this point in the history
  • Loading branch information
bqlin committed Dec 28, 2021
1 parent 96f70a4 commit 8983301
Show file tree
Hide file tree
Showing 29 changed files with 51 additions and 51 deletions.
6 changes: 3 additions & 3 deletions problems/0051.N皇后.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,

确定完约束条件,来看看究竟要怎么去搜索皇后们的位置,其实搜索皇后的位置,可以抽象为一棵树。

下面我用一个 3 * 3 的棋盘,将搜索过程抽象为一颗树,如图:
下面我用一个 3 * 3 的棋盘,将搜索过程抽象为一棵树,如图:

![51.N皇后](https://img-blog.csdnimg.cn/20210130182532303.jpg)

从图中,可以看出,二维矩阵中矩阵的高就是这颗树的高度,矩阵的宽就是树形结构中每一个节点的宽度。
从图中,可以看出,二维矩阵中矩阵的高就是这棵树的高度,矩阵的宽就是树形结构中每一个节点的宽度。

那么我们用皇后们的约束条件,来回溯搜索这颗树**只要搜索到了树的叶子节点,说明就找到了皇后们的合理位置了**
那么我们用皇后们的约束条件,来回溯搜索这棵树**只要搜索到了树的叶子节点,说明就找到了皇后们的合理位置了**

### 回溯三部曲

Expand Down
4 changes: 2 additions & 2 deletions problems/0062.不同路径.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@

这道题目,刚一看最直观的想法就是用图论里的深搜,来枚举出来有多少种路径。

注意题目中说机器人每次只能向下或者向右移动一步,那么其实**机器人走过的路径可以抽象为一颗二叉树,而叶子节点就是终点!**
注意题目中说机器人每次只能向下或者向右移动一步,那么其实**机器人走过的路径可以抽象为一棵二叉树,而叶子节点就是终点!**

如图举例:

Expand All @@ -76,7 +76,7 @@ public:
来分析一下时间复杂度,这个深搜的算法,其实就是要遍历整个二叉树。
这颗树的深度其实就是m+n-1(深度按从1开始计算)。
这棵树的深度其实就是m+n-1(深度按从1开始计算)。
那二叉树的节点个数就是 2^(m + n - 1) - 1。可以理解深搜的算法就是遍历了整个满二叉树(其实没有遍历整个满二叉树,只是近似而已)
Expand Down
2 changes: 1 addition & 1 deletion problems/0077.组合.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ public:

本篇我们准对求组合问题的回溯法代码做了剪枝优化,这个优化如果不画图的话,其实不好理解,也不好讲清楚。

所以我依然是把整个回溯过程抽象为一颗树形结构,然后可以直观的看出,剪枝究竟是剪的哪里。
所以我依然是把整个回溯过程抽象为一棵树形结构,然后可以直观的看出,剪枝究竟是剪的哪里。



Expand Down
2 changes: 1 addition & 1 deletion problems/0077.组合优化.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public:

本篇我们准对求组合问题的回溯法代码做了剪枝优化,这个优化如果不画图的话,其实不好理解,也不好讲清楚。

所以我依然是把整个回溯过程抽象为一颗树形结构,然后可以直观的看出,剪枝究竟是剪的哪里。
所以我依然是把整个回溯过程抽象为一棵树形结构,然后可以直观的看出,剪枝究竟是剪的哪里。

**就酱,学到了就帮Carl转发一下吧,让更多的同学知道这里!**

Expand Down
2 changes: 1 addition & 1 deletion problems/0078.子集.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public:

```
在注释中,可以发现可以不写终止条件,因为本来我们就要遍历整颗树
在注释中,可以发现可以不写终止条件,因为本来我们就要遍历整棵树
有的同学可能担心不写终止条件会不会无限递归?
Expand Down
2 changes: 1 addition & 1 deletion problems/0096.不同的二叉搜索树.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ j相当于是头结点的元素,从1遍历到i为止。

那么dp[0]应该是多少呢?

从定义上来讲,空节点也是一颗二叉树,也是一颗二叉搜索树,这是可以说得通的。
从定义上来讲,空节点也是一棵二叉树,也是一棵二叉搜索树,这是可以说得通的。

从递归公式上来讲,dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量] 中以j为头结点左子树节点数量为0,也需要dp[以j为头结点左子树节点数量] = 1, 否则乘法的结果就都变成0了。

Expand Down
14 changes: 7 additions & 7 deletions problems/0106.从中序与后序遍历序列构造二叉树.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来在切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。

如果让我们肉眼看两个序列,画一颗二叉树的话,应该分分钟都可以画出来。
如果让我们肉眼看两个序列,画一棵二叉树的话,应该分分钟都可以画出来。

流程如图:

Expand Down Expand Up @@ -540,13 +540,13 @@ public:
# 思考题
前序和中序可以唯一确定一颗二叉树
前序和中序可以唯一确定一棵二叉树
后序和中序可以唯一确定一颗二叉树
后序和中序可以唯一确定一棵二叉树
那么前序和后序可不可以唯一确定一颗二叉树呢
那么前序和后序可不可以唯一确定一棵二叉树呢
**前序和后序不能唯一确定一颗二叉树!**,因为没有中序遍历无法确定左右部分,也就是无法分割。
**前序和后序不能唯一确定一棵二叉树!**,因为没有中序遍历无法确定左右部分,也就是无法分割。
举一个例子:
Expand All @@ -558,7 +558,7 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。
那么tree1 和 tree2 的前序和后序完全相同,这是一棵树么,很明显是两棵树!
所以前序和后序不能唯一确定一颗二叉树
所以前序和后序不能唯一确定一棵二叉树
# 总结
Expand All @@ -570,7 +570,7 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。
大家遇到这种题目的时候,也要学会打日志来调试(如何打日志有时候也是个技术活),不要脑动模拟,脑动模拟很容易越想越乱。
最后我还给出了为什么前序和中序可以唯一确定一颗二叉树,后序和中序可以唯一确定一颗二叉树,而前序和后序却不行。
最后我还给出了为什么前序和中序可以唯一确定一棵二叉树,后序和中序可以唯一确定一棵二叉树,而前序和后序却不行。
认真研究完本篇,相信大家对二叉树的构造会清晰很多。
Expand Down
4 changes: 2 additions & 2 deletions problems/0108.将有序数组转换为二叉搜索树.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
做这道题目之前大家可以了解一下这几道:

* [106.从中序与后序遍历序列构造二叉树](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)
* [654.最大二叉树](https://programmercarl.com/0654.最大二叉树.html)中其实已经讲过了,如果根据数组构造一颗二叉树
* [654.最大二叉树](https://programmercarl.com/0654.最大二叉树.html)中其实已经讲过了,如果根据数组构造一棵二叉树
* [701.二叉搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)
* [450.删除二叉搜索树中的节点](https://programmercarl.com/0450.删除二叉搜索树中的节点.html)

Expand All @@ -36,7 +36,7 @@
其实这里不用强调平衡二叉搜索树,数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从数组中间位置取值作为节点元素,一般不会随机取,**所以想构成不平衡的二叉树是自找麻烦**


[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)[二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)中其实已经讲过了,如果根据数组构造一颗二叉树
[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)[二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)中其实已经讲过了,如果根据数组构造一棵二叉树

**本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间**

Expand Down
2 changes: 1 addition & 1 deletion problems/0110.平衡二叉树.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@

有的同学一定疑惑,为什么[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中求的是二叉树的最大深度,也用的是后序遍历。

**那是因为代码的逻辑其实是求的根节点的高度,而根节点的高度就是这颗树的最大深度,所以才可以使用后序遍历。**
**那是因为代码的逻辑其实是求的根节点的高度,而根节点的高度就是这棵树的最大深度,所以才可以使用后序遍历。**

[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中,如果真正求取二叉树的最大深度,代码应该写成如下:(前序遍历)

Expand Down
4 changes: 2 additions & 2 deletions problems/0112.路径总和.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@

再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:

* 如果需要搜索整颗二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
* 如果需要搜索整颗二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在[236. 二叉树的最近公共祖先](https://programmercarl.com/0236.二叉树的最近公共祖先.html)中介绍)
* 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
* 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在[236. 二叉树的最近公共祖先](https://programmercarl.com/0236.二叉树的最近公共祖先.html)中介绍)
* 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)

而本题我们要找一条符合条件的路径,所以递归函数需要返回值,及时返回,那么返回类型是什么呢?
Expand Down
2 changes: 1 addition & 1 deletion problems/0131.分割回文串.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

感受出来了不?

所以切割问题,也可以抽象为一颗树形结构,如图:
所以切割问题,也可以抽象为一棵树形结构,如图:

![131.分割回文串](https://code-thinking.cdn.bcebos.com/pics/131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.jpg)

Expand Down
6 changes: 3 additions & 3 deletions problems/0236.二叉树的最近公共祖先.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ left与right的逻辑处理;

**在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)**

那么为什么要遍历整颗树呢?直观上来看,找到最近公共祖先,直接一路返回就可以了。
那么为什么要遍历整棵树呢?直观上来看,找到最近公共祖先,直接一路返回就可以了。

如图:

Expand Down Expand Up @@ -161,7 +161,7 @@ else { // (left == NULL && right == NULL)

![236.二叉树的最近公共祖先2](https://img-blog.csdnimg.cn/202102041512582.png)

**从图中,大家可以看到,我们是如何回溯遍历整颗二叉树,将结果返回给头结点的!**
**从图中,大家可以看到,我们是如何回溯遍历整棵二叉树,将结果返回给头结点的!**

整体代码如下:

Expand Down Expand Up @@ -208,7 +208,7 @@ public:
1. 求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从低向上的遍历方式。
2. 在回溯的过程中,必然要遍历整颗二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
2. 在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
3. 要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果。
Expand Down
2 changes: 1 addition & 1 deletion problems/0347.前K个高频元素.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

什么是堆呢?

**堆是一颗完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。** 如果父亲结点是大于等于左右孩子就是大顶堆,小于等于左右孩子就是小顶堆。
**堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。** 如果父亲结点是大于等于左右孩子就是大顶堆,小于等于左右孩子就是小顶堆。

所以大家经常说的大顶堆(堆头是最大元素),小顶堆(堆头是最小元素),如果懒得自己实现的话,就直接用priority_queue(优先级队列)就可以了,底层实现都是一样的,从小到大排就是小顶堆,从大到小排就是大顶堆。

Expand Down
2 changes: 1 addition & 1 deletion problems/0450.删除二叉搜索树中的节点.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ if (root == nullptr) return root;

![450.删除二叉搜索树中的节点](https://tva1.sinaimg.cn/large/008eGmZEly1gnbj3k596mg30dq0aigyz.gif)

动画中颗二叉搜索树中,删除元素7, 那么删除节点(元素7)的左孩子就是5,删除节点(元素7)的右子树的最左面节点是元素8。
动画中棵二叉搜索树中,删除元素7, 那么删除节点(元素7)的左孩子就是5,删除节点(元素7)的右子树的最左面节点是元素8。

将删除节点(元素7)的左孩子放到删除节点(元素7)的右子树的最左面节点(元素8)的左孩子上,就是把5为根节点的子树移到了8的左孩子的位置。

Expand Down
4 changes: 2 additions & 2 deletions problems/0513.找树左下角的值.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ void traversal(TreeNode* root, int leftLen)
其实很多同学都对递归函数什么时候要有返回值,什么时候不能有返回值很迷茫。
**如果需要遍历整颗树,递归函数就不能有返回值。如果需要遍历某一条固定路线,递归函数就一定要有返回值!**
**如果需要遍历整棵树,递归函数就不能有返回值。如果需要遍历某一条固定路线,递归函数就一定要有返回值!**
初学者可能对这个结论不太理解,别急,后面我会安排一道题目专门讲递归函数的返回值问题。这里大家暂时先了解一下。
本题我们是要遍历整个树找到最深的叶子节点,需要遍历整颗树,所以递归函数没有返回值。
本题我们是要遍历整个树找到最深的叶子节点,需要遍历整棵树,所以递归函数没有返回值。
2. 确定终止条件
Expand Down
2 changes: 1 addition & 1 deletion problems/0538.把二叉搜索树转换为累加树.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

一看到累加树,相信很多小伙伴都会疑惑:如何累加?遇到一个节点,然后在遍历其他节点累加?怎么一想这么麻烦呢。

然后再发现这是一颗二叉搜索树,二叉搜索树啊,这是有序的啊。
然后再发现这是一棵二叉搜索树,二叉搜索树啊,这是有序的啊。

那么有序的元素如果求累加呢?

Expand Down
2 changes: 1 addition & 1 deletion problems/0617.合并二叉树.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ public:
合并二叉树,也是二叉树操作的经典题目,如果没有接触过的话,其实并不简单,因为我们习惯了操作一个二叉树,一起操作两个二叉树,还会有点懵懵的。
这不是我们第一次操作两颗二叉树了,在[二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html)中也一起操作了两棵二叉树。
这不是我们第一次操作两棵二叉树了,在[二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html)中也一起操作了两棵二叉树。
迭代法中,一般一起操作两个树都是使用队列模拟类似层序遍历,同时处理两个树的节点,这种方式最好理解,如果用模拟递归的思路的话,要复杂一些。
Expand Down
2 changes: 1 addition & 1 deletion problems/0685.冗余连接II.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

<img src='https://code-thinking.cdn.bcebos.com/pics/685.冗余连接II1.png' width=600> </img></div>

且只有一个节点入度为2,为什么不看出度呢,出度没有意义,一颗树中随便一个父节点就有多个出度
且只有一个节点入度为2,为什么不看出度呢,出度没有意义,一棵树中随便一个父节点就有多个出度


第三种情况是没有入度为2的点,那么图中一定出现了有向环(**注意这里强调是有向环!**
Expand Down
2 changes: 1 addition & 1 deletion problems/0701.二叉搜索树中的插入操作.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ if (root == NULL) {

此时要明确,需要遍历整棵树么?

别忘了这是搜索树,遍历整颗搜索树简直是对搜索树的侮辱,哈哈。
别忘了这是搜索树,遍历整棵搜索树简直是对搜索树的侮辱,哈哈。

搜索树是有方向了,可以根据插入元素的数值,决定递归方向。

Expand Down
2 changes: 1 addition & 1 deletion problems/前序/ACM模式如何构建二叉树.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210914222335.png)

一直跟着公众号学算法的录友 应该知道,我在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/Dza-fqjTyGrsRw4PWNKdxA),已经讲过,**只有 中序与后序 和 中序和前序 可以确定一颗唯一的二叉树。 前序和后序是不能确定唯一的二叉树的**
一直跟着公众号学算法的录友 应该知道,我在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/Dza-fqjTyGrsRw4PWNKdxA),已经讲过,**只有 中序与后序 和 中序和前序 可以确定一棵唯一的二叉树。 前序和后序是不能确定唯一的二叉树的**

那么[538.把二叉搜索树转换为累加树](https://mp.weixin.qq.com/s/rlJUFGCnXsIMX0Lg-fRpIw)的示例中,为什么,一个序列(数组或者是字符串)就可以确定二叉树了呢?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ int fibonacci(int i) {
在讲解递归时间复杂度的时候,我们提到了递归算法的时间复杂度本质上是要看: **递归的次数 * 每次递归的时间复杂度**。
可以看出上面的代码每次递归都是$O(1)$的操作。再来看递归了多少次,这里将i为5作为输入的递归过程 抽象成一颗递归树,如图:
可以看出上面的代码每次递归都是$O(1)$的操作。再来看递归了多少次,这里将i为5作为输入的递归过程 抽象成一棵递归树,如图:
![递归空间复杂度分析](https://img-blog.csdnimg.cn/20210305093200104.png)
从图中,可以看出f(5)是由f(4)和f(3)相加而来,那么f(4)是由f(3)和f(2)相加而来 以此类推。
在这颗二叉树中每一个节点都是一次递归,那么这棵树有多少个节点呢?
在这棵二叉树中每一个节点都是一次递归,那么这棵树有多少个节点呢?
我们之前也有说到,一棵深度(按根节点深度为1)为k的二叉树最多可以有 2^k - 1 个节点。
Expand Down
Loading

0 comments on commit 8983301

Please sign in to comment.