1110-删点成林

Raphael Liu Lv10

给出二叉树的根节点 root,树上每个节点都有一个不同的值。

如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。

返回森林中的每棵树。你可以按任意顺序组织答案。

示例 1:

![](https://assets.leetcode-cn.com/aliyun-lc-
upload/uploads/2019/07/05/screen-shot-2019-07-01-at-53836-pm.png)

**输入:** root = [1,2,3,4,5,6,7], to_delete = [3,5]
**输出:** [[1,2,null,4],[6],[7]]

示例 2:

**输入:** root = [1,2,4,null,3], to_delete = [3]
**输出:** [[1,2,4]]

提示:

  • 树中的节点数最大为 1000
  • 每个节点都有一个介于 11000 之间的值,且各不相同。
  • to_delete.length <= 1000
  • to_delete 包含一些从 11000、各不相同的值。

方法一:深度优先搜索

思路

题目给定一棵树 root,树的每个节点都有一个各不相同的值。并且给定一个数组 to_delete,包含需要删除的节点值。返回删除所有的 to_delete 中的节点后,剩余的树的集合。

可以利用深度优先搜索来遍历每一个节点,定义函数 dfs,输入是参数是某个节点 node 和这个节点是否为潜在的新的根节点 is_root。函数中,首先判断这个节点是否要被删除,如果是,那么它的两个子节点(如果有的话)便成为了潜在的根节点。如果这个节点的值不在 to_delete 中并且 is_root 为 true,那么这个节点便成为了一个新的根节点,需要把它放入结果数组中。同时也要对它的两个子节点进行同样的操作。dfs 的返回值为更新后的 node。

对根节点调用一次 dfs,返回新的根节点数组即可。

代码

[sol1-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
def delNodes(self, root: Optional[TreeNode], to_delete: List[int]) -> List[TreeNode]:
to_delete_set = set(to_delete)
roots = []
self.dfs(root, True, to_delete_set, roots)
return roots

def dfs(self, node: Optional[TreeNode], is_root: bool, to_delete_set: set[int], roots: List[TreeNode]) -> Optional[TreeNode]:
if node == None:
return None
delete = node.val in to_delete_set
node.left = self.dfs(node.left, delete, to_delete_set, roots)
node.right = self.dfs(node.right, delete, to_delete_set, roots)
if delete:
return None
else:
if is_root:
roots.append(node)
return node
[sol1-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public List<TreeNode> delNodes(TreeNode root, int[] to_delete) {
Set<Integer> toDeleteSet = new HashSet<Integer>();
for (int val : to_delete) {
toDeleteSet.add(val);
}
List<TreeNode> roots = new ArrayList<TreeNode>();
dfs(root, true, toDeleteSet, roots);
return roots;
}

public TreeNode dfs(TreeNode node, boolean isRoot, Set<Integer> toDeleteSet, List<TreeNode> roots) {
if (node == null) {
return null;
}
boolean deleted = toDeleteSet.contains(node.val);
node.left = dfs(node.left, deleted, toDeleteSet, roots);
node.right = dfs(node.right, deleted, toDeleteSet, roots);
if (deleted) {
return null;
} else {
if (isRoot) {
roots.add(node);
}
return node;
}
}
}
[sol1-Go]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func delNodes(root *TreeNode, to_delete []int) []*TreeNode {
toDeleteSet := make(map[int]bool)
for _, val := range to_delete {
toDeleteSet[val] = true
}
var roots []*TreeNode
dfs(root, true, toDeleteSet, &roots)
return roots
}

func dfs(node *TreeNode, isRoot bool, toDeleteSet map[int]bool, roots *[]*TreeNode) *TreeNode {
if node == nil {
return nil
}
deleted := toDeleteSet[node.Val]
node.Left = dfs(node.Left, deleted, toDeleteSet, roots)
node.Right = dfs(node.Right, deleted, toDeleteSet, roots)
if deleted {
return nil
} else {
if isRoot {
*roots = append(*roots, node)
}
return node
}
}
[sol1-JavaScript]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var delNodes = function(root, to_delete) {
const toDeleteSet = new Set(to_delete);
const roots = [];
dfs(root, true, toDeleteSet, roots);
return roots;
}

function dfs(node, isRoot, toDeleteSet, roots) {
if (!node) {
return null;
}
const deleted = toDeleteSet.has(node.val);
node.left = dfs(node.left, deleted, toDeleteSet, roots);
node.right = dfs(node.right, deleted, toDeleteSet, roots);
if (deleted) {
return null;
} else {
if (isRoot) {
roots.push(node);
}
return node;
}
}
[sol1-C#]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Solution {
public IList<TreeNode> DelNodes(TreeNode root, int[] to_delete) {
ISet<int> toDeleteSet = new HashSet<int>();
foreach (int val in to_delete) {
toDeleteSet.Add(val);
}
IList<TreeNode> roots = new List<TreeNode>();
DFS(root, true, toDeleteSet, roots);
return roots;
}

public TreeNode DFS(TreeNode node, bool isRoot, ISet<int> toDeleteSet, IList<TreeNode> roots) {
if (node == null) {
return null;
}
bool deleted = toDeleteSet.Contains(node.val);
node.left = DFS(node.left, deleted, toDeleteSet, roots);
node.right = DFS(node.right, deleted, toDeleteSet, roots);
if (deleted) {
return null;
} else {
if (isRoot) {
roots.Add(node);
}
return node;
}
}
}
[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public:
vector<TreeNode*> delNodes(TreeNode* root, vector<int>& to_delete) {
unordered_set<int> to_delete_set(to_delete.begin(), to_delete.end());
vector<TreeNode *> roots;

function<TreeNode *(TreeNode *, bool)> dfs = [&](TreeNode* node, bool is_root) -> TreeNode * {
if (node == nullptr) {
return nullptr;
}
bool deleted = to_delete_set.count(node->val) ? true : false;
node->left = dfs(node->left, deleted);
node->right = dfs(node->right, deleted);
if (deleted) {
return nullptr;
} else {
if (is_root) {
roots.emplace_back(node);
}
return node;
}
};

dfs(root, true);
return roots;
}
};
[sol1-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#define MAX_NODES 1000

typedef struct {
int key;
UT_hash_handle hh;
} HashItem;

HashItem *hashFindItem(HashItem **obj, int key) {
HashItem *pEntry = NULL;
HASH_FIND_INT(*obj, &key, pEntry);
return pEntry;
}

bool hashAddItem(HashItem **obj, int key) {
if (hashFindItem(obj, key)) {
return false;
}
HashItem *pEntry = (HashItem *)malloc(sizeof(HashItem));
pEntry->key = key;
HASH_ADD_INT(*obj, key, pEntry);
return true;
}

void hashFree(HashItem **obj) {
HashItem *curr = NULL, *tmp = NULL;
HASH_ITER(hh, *obj, curr, tmp) {
HASH_DEL(*obj, curr);
free(curr);
}
}

struct TreeNode* dfs(struct TreeNode* node, bool is_root, const HashItem *to_delete_set, struct TreeNode** roots, int *pos) {
if (node == NULL) {
return NULL;
}
bool deleted = hashFindItem(&to_delete_set, node->val) != NULL ? true : false;
node->left = dfs(node->left, deleted, to_delete_set, roots, pos);
node->right = dfs(node->right, deleted, to_delete_set, roots, pos);
if (deleted) {
return NULL;
} else {
if (is_root) {
roots[(*pos)++] = node;
}
return node;
}
};

struct TreeNode** delNodes(struct TreeNode* root, int* to_delete, int to_deleteSize, int* returnSize) {
struct TreeNode** roots = (struct TreeNode**)malloc(sizeof(struct TreeNode *) * MAX_NODES);
int pos = 0;
HashItem *to_delete_set = NULL;
for (int i = 0; i < to_deleteSize; i++) {
hashAddItem(&to_delete_set, to_delete[i]);
}
dfs(root, true, to_delete_set, roots, &pos);
*returnSize = pos;
hashFree(&to_delete_set);
return roots;
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是树的节点数。

  • 空间复杂度:O(n),其中 n 是树的节点数。

 Comments
On this page
1110-删点成林