递归
首先知道 题目问的整个树的最大的深度 = root 的高度 这样用post-order 写起来会很方便
为什么Post - order? 处理完子树之后,再 把数值(本题中是高度) 传递给他们的父结点,一层层想上传递信息
相反,pre-order 是先处理好上层逻辑再把需要的数据向下传递.
文字表述过程:
- 先找左边,
- 再找右边,(
(左右顺序不重要,只要找到之后返回上去即可) - 最后拿到了左右子树高度的信息,取到最大值 + 1(本层逻辑)
递归
首先,这道题也可以用后序遍历解决。
但是有一个问题,当我们取最小值的时候,一旦有空子树(即depth =0 )因为取最小值, 它就会被选中
而题目的要求是不考虑无子树的条件/距离最近的子节点。
所以直接的解法就是在取height值的时候,把这种特殊情况考虑进来去掉
如何在代码里体现?
首先是general 的情况: 左右都有node: 逻辑就和最大深度十分相似: minDepth(left ,right) +1
corner case就是: 左子树为空[左右枝丫都没有], 右不为空: 为空的话,就不需要考虑这边的节点,直接返回另一边的height即可
- 基本版本
思路非常的简单,遍历,并且无论何种遍历都可以解决。
而在每次遍历的基础上,把数到的这个点算进去(自己 + 1)。
自己没想到,还蠢蠢的跑去数单次递归下的结点的左右子树。其实直接把当前 +1 就完成了count…
二刷的我,果不其然 又又又去数点了,我用了递归遍历中最古老繁琐的方法: 定义全局变量res, 利用一个递归(辅助)函数(返回void 因为是对全局变量进行操作)去数点,最后把res 返回即可。
- 升级版本
因为他给定了该tree一定是完全二叉树, 那也就是说子节点从左到右一定是连续的 ,这是前提。
之后比较巧妙:如果我们可以判断出来是满二叉树的话,直接用公式计算即可。那如何判断是满二叉树呢?只要一直往左边和右边循环走到头,算出来的Height 是相等的。那中间肯定是满的(运用了完全二叉树的特性) 直接返回 2^n - 1即可,如果不相等,那就正常递归,最后肯定会有一个满2叉数否则为Null 直接就返回0了, 这样也不会一直在循环里不出来。
代码的实现着实又为难了我一把,先理解递归+ 循环的写法:
1,root为空的话,直接返回0。2, 进入到每一层先进行循环的计算看左边和最右边的height是否一样? 一样就可以返回 (1 << left ) 不一样的话就乖乖的进行常规遍历
if(leftH = rightH)
return (int) Math.pow(2, leftH) - 1;
else
return count(root.left) + count( root.right) + 1
- 升级v2,更巧妙的方法:
- 数count的时候,根据 完全二叉树的性质:其实只要一直向左走,就可以获得最大深度。
- 得到的height 有2种情况,高度相等 OR 不相等。[记住,处理单层递归,我得到的是上一层给我的返回值,也就是说是上一层的depth]
- 相等: 左边上层节点和[ 2^ld -1]+当前左根节点[1]+右总结点[Count(root.right)] 。
- 不相等:(右边的上层节点一定是个满2叉)右边上层节点和 [2^rd - 1] + 左边的当前根节点[1] +左总节点[Count(root.left)]
Ps: 通过这几道题,记一下自己对于递归的理解,还是有点迷茫,如果之后继续刷树会有更深的理解在跑过来更新。 从 root 开始向下进发,所以会有root.left Or root.right 这些下一个阶段需要用的值作为参数放到递归函数里。
但是一个个回退(return)的时候, 以数的理解是从下往上回收数据。所以拿到的都是上一层的数据结果。
所以就像是,送进去的是 i +1 拿回来的也是他的返回,拿到之后我再做自己的逻辑运算