0.前置知识:
二叉树中的深搜
深度优先遍历(DFS,全称呼为Depth First Traversal),是我们树或者图这样的数据结构中常用到的一种遍历算法。这个算法会尽可能的深的搜索树或者图的分支,直到一条路径上的所有节点都被遍历完毕,然后再回溯到上一层,继续找一条路遍历。
在二叉树中,常见的深度优先遍历为:前序遍历、中序遍历以及后序遍历。
因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简介。并且前中后序三种遍历的唯一区别就是访问根节点的时机不同,在做题的时候,选择一个合适的遍历顺序,对于算法的理解是非常有帮助的。
1.题目链接:
2.题目描述:
给你一棵 完整二叉树 的根,这棵树有以下特征:
叶子节点 要么值为 0 要么值为 1 ,其中 0 表示 False ,1 表示 True 。
非叶子节点 要么值为 2 要么值为 3 ,其中 2 表示逻辑或 OR ,3 表示逻辑与 AND 。 计算 一个节点的值方式如下:
如果节点是个叶子节点,那么节点的 值 为它本身,即 True 或者 False 。
否则,计算 两个孩子的节点值,然后将该节点的运算符对两个孩子值进行 运算 。 返回根节点 root 的布尔运算值。
完整二叉树 是每个节点有 0 个或者 2 个孩子的二叉树。
叶子节点 是没有孩子的节点。
示例1:
输入:root = [2,1,3,null,null,0,1]
输出:true
解释:上图展示了计算过程。
AND 与运算节点的值为 False AND True = False 。
OR 运算节点的值为 True OR False = True 。
根节点的值为 True ,所以我们返回 true 。
示例2:
输入:root = [0]
输出:false
解释:根节点是叶子节点,且值为 false,所以我们返回 false 。
提示:
树中节点数目在 [1, 1000] 之间。
0 <= Node.val <= 3
每个节点的孩子数为 0 或 2 。
叶子节点的值为 0 或 1 。
非叶子节点的值为 2 或 3 。
3. 解法(递归):
算法思路:
算法思路:
本题可以被解释为:
1. 对于规模为 n 的问题,需要求得当前节点值。
2. 节点值不为 0 或 1 时,规模为 n 的问题可以被拆分为规模为 n-1 的子问题:
a. 所有子节点的值;
b. 通过子节点的值运算出当前节点值。
3. 当问题的规模变为 n=1 时,即叶子节点的值为 0 或 1,我们可以直接获取当前节点值为 0 或 1。
算法流程:
递归函数设计:bool evaluateTree(TreeNode* root)
1. 返回值:当前节点值;
2. 参数:当前节点指针。
3. 函数作用:求得当前节点通过逻辑运算符得出的值。
递归函数流程:
1. 当前问题规模为 n=1 时,即叶子节点,直接返回当前节点值;
2. 递归求得左右子节点的值;
3. 通过判断当前节点的逻辑运算符,计算左右子节点值运算得出的结果;
需要注意的是,这里采用后序遍历(也就是 左右根)
最后访问根节点,因为根节点的计算,依赖于左右节点(也就是左右子树)。
Java算法代码:
class Solution {
public boolean evaluateTree(TreeNode root) {
if(root.left == null ) return root.val ==0 ? false : true;
boolean left = evaluateTree(root.left);
boolean right = evaluateTree(root.right);
return root.val == 2 ? left | right : left & right;
}
}
运行结果:
递归展开(后序遍历):
逻辑展开:
这里根据根节点需要依赖左右节点的值(所以选择了后序遍历)
体现呢????
后序遍历:左右根
代码的执行顺序是,先左子树递归,然后右子树递归,最后,执行根节点的操作。(符合左右根)
然后递归出口的位置呢??因为这个可能左右都是null,也就一进来就是符合返回逻辑了。并不需要进行处理,所以这里的出口放到了递归的开始。可以去试试,放在其他的地方呢??
---------------------------------------------------------------------------------------------------------------------------------
记住,相信你的递归函数,它可以做到!
记住,不理解时候,去尝试手动展开!
记住,逻辑展开(你不可能对所有的题目都进行手动展开)!