[二叉树] 删点成林

前言

之前一直做得题目是在一棵树上捯饬,今天做一道把二叉树变为森林的题目,多点捯饬的空间。

题目

删点成林

//给出二叉树的根节点 root,树上每个节点都有一个不同的值。 
//
// 如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。 
//
// 返回森林中的每棵树。你可以按任意顺序组织答案。 
//
// 
//
// 示例: 
//
// 
//
// 输入:root = [1,2,3,4,5,6,7], to_delete = [3,5]
//输出:[[1,2,null,4],[6],[7]]
// 
//
// 
//
// 提示: 
//
// 
// 树中的节点数最大为 1000。 
// 每个节点都有一个介于 1 到 1000 之间的值,且各不相同。 
// to_delete.length <= 1000 
// to_delete 包含一些从 1 到 1000、各不相同的值。

题目拆解

这道题目简单来看和二叉搜索树的删除节点有点像,但是这里面不需要替换节点,节点删掉就直接砍断,斩断情丝,斩断牵挂。

但是不需要替换节点,其实也没有变得简单,因为分为两段以后,还要继续找被删除的节点,所以,最终可能也想蚯蚓一样,切成很多段...为啥今天总是要用奇怪的比喻。

好,那继续拆解这个题目,由上述可知,二叉树被切分的关键点在于是否找到了和待删除目标值相同的节点,找到了,就从这个地方一分为二,并且把父节点指向当前节点的指针清空。所以我们定义一个节点的两个状态

  • 1节点被删除了
  • 2 节点还在

在dfs遍历的时候,将这种状态告诉父节点,然后让父节点吧对应的指针清除掉。
如果节点还在,那就直接处理子节点,然后把当前节点返回即可。

代码一阶段

class Solution {

    Set<Integer> deleteMap = new HashSet<>();
    List<TreeNode> res = new ArrayList<>();

    public List<TreeNode> delNodes(TreeNode root, int[] to_delete) {
        for (int i : to_delete) {
            deleteMap.add(i);
        }

        TreeNode dummyNode= new TreeNode(-1);
        dummyNode.left = root;
        int rootRes = delNodes(root,dummyNode,true);
        if (rootRes == 2) {
            res.add(dummyNode.left);
        }
        return res;

    }

    int delNodes(TreeNode node, TreeNode parent, boolean isLeft) {
        // 返回状态
        // 1 节点没了
        // 2 还有货
        // 如果为空,代表状态1,节点没了
        if (node == null) return 1;
        // 如果是待删除节点,删除后节点也没了
        if (deleteMap.contains(node.val)) {
            // 把父节点指向自己的链接删掉
            if (isLeft) parent.left = null;
            if (!isLeft) parent.right = null;
            // 将不为空的子树,插入结果集
            int leftRes = delNodes(node.left, node, true);
            if (leftRes == 2) res.add(node.left);
            node.left = null;
            int rightRes = delNodes(node.right, node, false);
            if (rightRes == 2) res.add(node.right);
            node.right = null;
            return 1;
        } else {
            // 如果子树为空,将指针清除
            int leftRes = delNodes(node.left, node, true);
            if (leftRes == 1) {
                node.left = null;
            }
            int rightRes = delNodes(node.right, node, false);
            if (rightRes == 1) {
                node.right = null;
            }

            return 2;
        }
    }
}

第一版的代码写的还是有很多繁琐的地方,比如在递归时候引入的变量很多,还要给root节点设置一个哑结点,还有很多状态的判断,实际上,因为只有两种状态,所以只需要根据dfs返回的节点是否为null来判断即可,多余的父节点其实可以通过返回结果让父节点直接处理就可以了,不需要当前节点来做多余的事情,所以,我们来到了

代码二阶段

class Solution {

    Set<Integer> deleteMap = new HashSet<>();
    List<TreeNode> res = new ArrayList<>();

    public List<TreeNode> delNodes(TreeNode root, int[] to_delete) {
        for (int i : to_delete) {
            deleteMap.add(i);
        }


        root = delNodes(root);
        if (root != null) {
            res.add(root);
        }
        return res;


    }
    
    TreeNode delNodes(TreeNode node) {

        // 如果节点为null, 返回null
        if (node == null) return null;
        // 如果当前节点的值和是需要删除的节点,将左右子树中,不为空的插入结果集
        if (deleteMap.contains(node.val)) {
            TreeNode left = delNodes(node.left);
            if (left != null) res.add(node.left);
            TreeNode right = delNodes(node.right);
            if (right != null) res.add(node.right);
            return null;
        } else {
            // 如果当前节点不是待删除节点,处理子树,同时返回当前节点
            node.left = delNodes(node.left);
            node.right = delNodes(node.right);
            return node;
        }
    }
}

总结

以上就是本地的解析和题解,今天一点小收获是想保证一次代码bugfree可以吧流程拉长一点,尽可能保证多的覆盖,比如一阶段的代码,其实父节点指向子节点指针置空的处理有些多余,但是这么写也更加直观和稳妥,在二阶段优化的时候,重点在于如何吧逻辑优化,让代码看起来更简洁明了。

其实两阶段代码的执行时间差不多,只是看起来确实更加清爽了些。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容