【树】力扣1110:删点成林
作者:互联网
给出二叉树的根节点 root,树上每个节点都有一个不同的值。
如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。
返回森林中的每棵树。你可以按任意顺序组织答案。
示例:
输入:root = [1,2,3,4,5,6,7], to_delete = [3,5]
输出:[[1,2,null,4],[6],[7]]
第一次遇到没有官方题解的题~
输入是一个整数二叉树和一个一维整数数组,输出一个数组,每个位置存储一个子树(的根节点)。
二叉树的题大多可以用递归,从而想到深度优先搜索DFS。
后序遍历
对于被删除节点类型,可以分情况进行分析:
-
叶子节点:直接删掉
-
非叶子节点:如果左右子树不为空,就将左右子树加入结果集
为了得到这个结果集,每个结点需要做什么?
- 每个结点要知道自己是否需要被删掉,如果需要被删掉,那么就根据情况执行上一步的分析
在什么时候做这些事?
- 如果一个结点需要被删掉,那么应该将它与父节点的关系进行移除,所以需要:判断完结点是否需要被删除后,告知其父节点进行相应的指针操作
那么不妨采用后序遍历的方式,定义一个删除函数:删除以 node 为根结点的树中结点值出现在 to_delete 中的结点,更新结果 ans,并返回删除后新的根结点。
在执行这个删除函数之前,需要做什么准备工作呢?
-
将最初的根结点加入结果集
- 这么做的原因是:如果没有要删除的结点,那么删除函数是不会将根结点加入结果集的,所以需要提前加入 root 结点。在删除函数中会维护指针索引,所以结果集中的树结构会保证正确
-
为了减少搜索 to_delete 的时间,可以将数组转换为 set
时间复杂度:O(N),其中 N 为树的结点个数。
空间复杂度:O(N)。
前序遍历
如果在递归过程中修改二叉树结构,必须要让父结点接收递归函数的返回值。
可以通过函数参数传递父结点传递的数据,所以可以在前序位置判断是否得到了一个新的根结点。
@ JavaScript
/**
* @param {TreeNode} root
* @param {number[]} to_delete
* @return {TreeNode[]}
*/
var delNodes = function (root, to_delete) {
let delSet = new Set();
// 记录森林的根节点
let res = [];
if (root == null) return [];
for (let d of to_delete) {
delSet.add(d);
}
// 定义:输入一棵二叉树,删除 delSet 中的节点,返回删除完成后的根节点
const doDelete = (root, hasParent) => {
if (root == null) return null;
// 判断是否需要被删除
let deleted = delSet.has(root.val);
if (!deleted && !hasParent) {
// 没有父节点且不需要被删除,就是一个新的根节点
res.push(root);
}
// 去左右子树进行删除
root.left = doDelete(root.left, !deleted);
root.right = doDelete(root.right, !deleted);
// 如果需要被删除,返回 null 给父节点
return deleted ? null : root;
};
doDelete(root, false);
return res;
};
作者:angela-x
链接:https://leetcode.cn/problems/delete-nodes-and-return-forest/solution/qian-xu-bian-li-lai-jie-jue-shan-dian-ch-l3h4/
标签:结点,return,删除,力扣,1110,删点,root,节点,delete 来源: https://www.cnblogs.com/Jojo-L/p/16487901.html