LeetCode814 二叉树剪枝
剪枝:剪枝顾名思义就是对一棵树进行修修剪剪,现实中我们对树进行修剪的目的是为了让其更好看,而在程序中对二叉树进行操作也是如此的,在程序中所谓的“好看”即是可以减少算法的时间复杂度。剪枝好像在决策树,机器学习过度拟合等领域都有用到,但是我并不了解剪枝在真正场景中的使用,仅仅只是在做题的角度上有所了解(害)。
题目描述
给定二叉树根节点root,此外树的每个结点的值要么是 0,要么是 1.
返回移除所有不包含1的子树的原二叉树
节点x的子树包含节点x本身和所有x的后代
说明:
给定的二叉树最多有100个节点
每个节点的值只会为0或1
示例
-
输入:[1,null,0,0,1]
输出:[1,null,0,null,1]
图示:
说明:
只有红色那个0满足“所有子树节点不包含1”,另外一个0其右子树明显有个1,所以不用删除,要注意的是题目给出的规定是:节点x的子树包含节点x本身和所有x的后代
-
输入:[1,0,1,0,0,0,1]
输出:[1,null,1,null,1]
-
输入:[1,1,0,1,1,0,1,0]
输出:[1,1,0,1,1,null,1]
图示:
题目解析
由上面的示例可以看出,每个被删除的节点的值为0,并且其左右子树都为“空”,即是“叶子节点”。拿示例2来看,如果我们采用递归的方式进行删除,递归栈首先操作最后一个入栈的节点,即递归方式是自底向上进行操作的。这样当正式处理示例2中的第二节点0(从左往右算)时,其左右子树的两个0都已经被删除掉了,所以这个节点同样的也可以删除,重复这样的过程即可删除所有满足条件的节点。递归实现的代码很简洁,代码如下:
class Solution {
public TreeNode pruneTree(TreeNode root) {
if (root == null) {
return null;
}
root.left = pruneTree(root.left); // 获取对左子树剪枝后的新子树
root.right = pruneTree(root.right); //获取对右子树剪枝后的新子树
if (root.left == null && root.right == null && root.val == 0) { //左右子树为空且值为0,要删除,返回null即可
return null;
}
return root;
}
}
程序运行结果:
注:虽然形式很简单,但是关键还是在于理解递归的运算过程。
更多题解请看原题:814.二叉树剪枝