在二叉树:以为使用了递归,其实还隐藏着回溯中,通过leetcode 257.二叉树的所有路径这道题目,讲解了递归如何隐藏着回溯,一些代码会把回溯的过程都隐藏了起来了,甚至刷过这道题的同学可能都不知道自己用了回溯。
文章中第一版代码把每一个细节都展示了输出来了,大家可以清晰的看到回溯的过程。
然后给出了第二版优化后的代码,分析了其回溯隐藏在了哪里,如果要把这个回溯扣出来的话,在第二版的基础上应该怎么改。
主要需要理解:回溯隐藏在traversal(cur->left, path + "->", result);中的 path + "->"。 每次函数调用完,path依然是没有加上"->" 的,这就是回溯了。
在文章二叉树:做了这么多题目了,我的左叶子之和是多少? 中提供了另一个判断节点属性的思路,平时我们习惯了使用通过节点的左右孩子判断本节点的属性,但发现使用这个思路无法判断左叶子。
此时需要相连的三层之间构成的约束条件,也就是要通过节点的父节点以及孩子节点来判断本节点的属性。
这道题目可以扩展大家对二叉树的解题思路。
在二叉树:我的左下角的值是多少?中的题目如果使用递归的写法还是有点难度的,层次遍历反而很简单。
题目其实就是要在树的最后一行找到最左边的值。
如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。
在这篇文章中,我们使用递归算法实实在在的求了一次深度,然后使用靠左的遍历,保证求得靠左的最大深度,而且又一次使用了回溯。
如果对二叉树的高度与深度又有点模糊了,在看这里二叉树:我平衡么?,回忆一下吧。
二叉树:我的左下角的值是多少?中把我们之前讲过的内容都过了一遍,此外,还用前序遍历的技巧求得了靠左的最大深度。
求二叉树的各种最值,就想应该采用什么样的遍历顺序,确定了遍历循序,其实就和数组求最值一样容易了。
在二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?中通过两道题目,彻底说清楚递归函数的返回值问题。
一般情况下:如果需要搜索整棵二叉树,那么递归函数就不要返回值,如果要搜索其中一条符合条件的路径,递归函数就需要返回值,因为遇到符合条件的路径了就要及时返回。
特别是有些时候 递归函数的返回值是bool类型,一些同学会疑惑为啥要加这个,其实就是为了找到一条边立刻返回。
其实还有一种就是后序遍历需要根据左右递归的返回值推出中间节点的状态,这种需要有返回值,例如222.完全二叉树,110.平衡二叉树,这几道我们之前也讲过。
之前都是讲解遍历二叉树,这次该构造二叉树了,在二叉树:构造二叉树登场!中,我们通过前序和中序,后序和中序,构造了唯一的一棵二叉树。
构造二叉树有三个注意的点:
- 分割时候,坚持区间不变量原则,左闭右开,或者左闭右闭。
- 分割的时候,注意后序 或者 前序已经有一个节点作为中间节点了,不能继续使用了。
- 如何使用切割后的后序数组来切合中序数组?利用中序数组大小一定是和后序数组的大小相同这一特点来进行切割。
这道题目代码实现并不简单,大家啃下来之后,二叉树的构造应该不是问题了。
最后我还给出了为什么前序和后序不能唯一构成一棵二叉树,因为没有中序遍历就无法确定左右部分,也就无法分割。
知道了如何构造二叉树,那么使用一个套路就可以解决文章二叉树:构造一棵最大的二叉树中的问题。
注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下标索引直接在原数组上操作,这样可以节约时间和空间上的开销。
文章中我还给出了递归函数什么时候加if,什么时候不加if,其实就是控制空节点(空指针)是否进入递归,是不同的代码实现方式,都是可以的。
一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整。
本周我们深度讲解了如下知识点:
- 递归中如何隐藏着回溯
- 如何通过三层关系确定左叶子
- 如何通过二叉树深度来判断左下角的值
- 递归函数究竟什么时候需要返回值,什么时候不要返回值?
- 前序和中序,后序和中序构造唯一二叉树
- 使用数组构造某一特性的二叉树
如果大家一路跟下来,一定收获满满,如果周末不做这个总结,大家可能都不知道自己收获满满,啊哈!