Leetcode 剑指 Offer II 047. 二叉树剪枝

题目难度: 中等

原题链接

今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

给定一个二叉树 根节点 root ,树的每个节点的值要么是 0,要么是 1。请剪除该二叉树中所有节点的值为 0 的子树。

节点 node 的子树为 node 本身,以及所有 node 的后代。

示例 1:

  • 输入: [1,null,0,0,1]

  • 输出: [1,null,0,null,1]

  • 解释: 只有红色节点满足条件“所有不包含 1 的子树”。 右图为返回的答案。

示例 2:

  • 输入: [1,0,1,0,0,0,1]
  • 输出: [1,null,1,null,1]
  • 解释:

示例 3:

  • 输入: [1,1,0,1,1,0,1,0]
  • 输出: [1,1,0,1,1,null,1]
  • 解释:

提示:

  • 二叉树的节点个数的范围是 [1,200]
  • 二叉树节点的值只会是 0 或 1

题目思考

  1. 如何在得到子树所有节点值的同时, 进行剪除操作?

解决方案

思路

  • 分析题目, 如果某个子树的所有节点都是 0, 则其根节点的值为 0, 且左右子树的所有节点也都是 0
  • 我们可以根据这一点, 使用 DFS 来判断, 具体做法如下:
    1. dfs 函数传入节点 node 作为参数, 返回以该节点为根的子树的所有节点是否全为 0
    2. 如果传入是空节点, 则返回 true, 作为递归出口
    3. 否则先递归调用 dfs 函数, 传入其左右子节点, 从而得到左右子树是否全为 0 的两个布尔值: leftAllZero 和 rightAllZero
    4. 那么当前子树要想全为 0, 就需要 node.val==0 && leftAllZero && rightAllZero, 返回它即可
  • 上述步骤只是得出了每个子树的所有节点是否全 0, 题目还要求剪除全 0 子树, 如何操作呢?
  • 我们可以在上面的第三步和第四步之间加入剪除操作:
    • 如果左子树全 0, 就断开当前节点和其左子节点的连接
    • 如果右子树全 0, 就断开当前节点和其右子节点的连接
  • 这样就在得到子树所有节点值的同时, 进行了剪除操作
  • 需要注意有可能整棵树的所有节点全为 0, 此时剪除后需要返回空节点
  • 我们可以引入一个哨兵节点, 将其左子节点指向整棵树的根节点
  • 然后从哨兵节点开始判断, 最终返回哨兵的左子节点, 这样就无需针对根节点做特殊处理了
  • 下面的代码就对应了上面的整个过程, 并且有详细的注释, 方便大家理解

复杂度

  • 时间复杂度 O(N): 需要遍历每个节点一遍
  • 空间复杂度 O(H): H 是树的高度, 也是递归栈的空间消耗

代码

class Solution:
    def pruneTree(self, root: TreeNode) -> TreeNode:
        # 使用哨兵节点, 将其左子节点指向root, 并从哨兵开始判断
        # 因为有可能整个树都是0, 此时需要返回空节点, 如果不用哨兵从root开始判断, 就需要额外的逻辑特殊处理root
        dummy = TreeNode(0, root)

        def allZero(node):
            if not node:
                # 递归出口, 空节点的值不是1, 所以返回True
                return True
            leftAllZero = allZero(node.left)
            rightAllZero = allZero(node.right)
            if leftAllZero:
                # 左子树全为0, 断开当前节点与其的连接
                node.left = None
            if rightAllZero:
                # 右子树全为0, 断开当前节点与其的连接
                node.right = None
            # 当前子树全为0需要满足: 当前节点值为0 && 左子树全为0 && 右子树全为0
            return node.val == 0 and leftAllZero and rightAllZero

        allZero(dummy)
        # 最终哨兵节点的左子节点即为删除全0子树后的根节点 (可能为空)
        return dummy.left

大家可以在下面这些地方找到我~😊

我的 GitHub

我的 Leetcode

我的 CSDN

我的知乎专栏

我的头条号

我的牛客网博客

我的公众号: 算法精选, 欢迎大家扫码关注~😊

算法精选 - 微信扫一扫关注我

全部评论

相关推荐

阿里巴巴各部门年终奖开奖了,有人拿到了220w
真烦好烦真烦:拿命换钱呢,公司给你220万,肯定是因为你对公司的贡献大于220万,想想要多厉害多累才能达到
投递阿里巴巴集团等公司10个岗位 >
点赞 评论 收藏
分享
永远年轻_永远热泪盈眶:咱们真是苦难哥俩,我是浙大宁理,你是浙大城院,测试学历卡得不严,之前携程实习,只能说确实wlb,但携程学历厂,当时我mentor面试官,给我们看了他面试的六个人,全是研究生,学历最烂的一个都是杭电研究生,复旦华科一堆
点赞 评论 收藏
分享
ResourceUtilization:四六级不愧是大学最有用的证之一
点赞 评论 收藏
分享
我是985研究生,最近学校在组织开题,大家都在非常紧张地准备,但我一直进入不了状态,很想做但是心又很浮躁。但我的室友们感觉都非常认真,每天醒来就开始看论文,睡着前最后一件事还是在看论文,我非常焦虑。我感觉自己甚至有点把大家当做假想敌了。这种比较心态还存在于生活的各种方面:看到有钱的同学会非常羡慕,看到朋友圈里面环游世界的留学生同学也会羡慕,看到那些工作后有自己的钱而过上较为阔绰的生活的时候还是羡慕,就仿佛只有自己一个人在阴暗爬行。而且这些比较是每时每刻的,为了不比较,我已经关闭了朋友圈,但是每次偶尔刷一下还是会难受很久。我知道比较是偷走幸福的小偷,但我好像控制不了,感觉自己是一个偷窥别人生活的...
若怜君欢:担心开题搞砸了,幻想拥有别人的生活,本质上是因为自卑,楼主小时候大概率是留守儿童或者父母关系很紧张,导致楼主没有安全感、焦虑、内耗。 这样的情况最好的办法就是建立自信和降低期待,建立自信不是一蹴而就,而是循序渐进,比如告诉自己允许自己第一次没把事情做好,失败了能搞清楚其中缘由而不是全盘否定自己,失败不是终点,放弃才是;降低期待只要记住一句话即可,能伴随你一生的,只有经验和学识,所以你对事情的态度应该更多地去思考它是否能带来学识和经验的增长,而不是仅仅用短期的利益作为唯一期待。 人生不是一成不变的,它是可以迭代更新的,去归纳总结自身的不足并结合实际去改进,去尝试一些新的思路和方法,不要固执钻牛角尖,也不要反复横跳,为自己设立一个高度聚集的精神内核,内核之上可以去尝试一切有利于自己更好的方式 以上就是我个人对生活的理解,共勉
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务