Medium
题目描述
给出二叉树的根节点 root,树中每个节点都有一个不同的值。
如果节点值在 to_delete 数组中出现,我们就把该节点从树中删去,最后得到一个森林(一些不相交的树构成的集合)。
返回森林中的每棵树的根节点。你可以按任意顺序返回结果。
示例 1:
输入: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个节点。 - 每个节点都有一个在
1到1000之间的不同的值。 to_delete.length <= 1000to_delete包含1到1000之间的不同的值。
解题思路
这道题的核心思想是通过深度优先搜索(DFS)来处理树的删除操作。
基本思路:
- 将待删除的节点值存入哈希表,便于快速查找
- 使用DFS遍历整棵树,对于每个节点判断是否需要删除
- 如果当前节点需要删除,则其左右子树(如果存在且不需要删除)将成为新的树根
- 如果当前节点不需要删除,则继续递归处理其子树
关键点分析:
- 当一个节点被删除时,需要将其从父节点断开连接
- 被删除节点的子树可能成为新的独立树
- 需要正确处理根节点被删除的情况
算法步骤:
- 创建哈希表存储待删除的值
- 编写递归函数,返回处理后的节点(可能为null)
- 在递归中,先处理子树,再判断当前节点
- 如果当前节点需要删除,将其非空子树加入结果集
- 最后处理根节点的特殊情况
这种方法能够一次遍历完成所有删除操作,时间复杂度为O(n)。
代码实现
class Solution {
public:
vector<TreeNode*> delNodes(TreeNode* root, vector<int>& to_delete) {
unordered_set<int> deleteSet(to_delete.begin(), to_delete.end());
vector<TreeNode*> result;
TreeNode* newRoot = dfs(root, deleteSet, result);
if (newRoot) {
result.push_back(newRoot);
}
return result;
}
private:
TreeNode* dfs(TreeNode* node, unordered_set<int>& deleteSet, vector<TreeNode*>& result) {
if (!node) return nullptr;
node->left = dfs(node->left, deleteSet, result);
node->right = dfs(node->right, deleteSet, result);
if (deleteSet.count(node->val)) {
if (node->left) result.push_back(node->left);
if (node->right) result.push_back(node->right);
return nullptr;
}
return node;
}
};
class Solution:
def delNodes(self, root: Optional[TreeNode], to_delete: List[int]) -> List[TreeNode]:
delete_set = set(to_delete)
result = []
def dfs(node):
if not node:
return None
node.left = dfs(node.left)
node.right = dfs(node.right)
if node.val in delete_set:
if node.left:
result.append(node.left)
if node.right:
result.append(node.right)
return None
return node
new_root = dfs(root)
if new_root:
result.append(new_root)
return result
public class Solution {
public IList<TreeNode> DelNodes(TreeNode root, int[] to_delete) {
HashSet<int> deleteSet = new HashSet<int>(to_delete);
List<TreeNode> result = new List<TreeNode>();
TreeNode newRoot = DFS(root, deleteSet, result);
if (newRoot != null) {
result.Add(newRoot);
}
return result;
}
private TreeNode DFS(TreeNode node, HashSet<int> deleteSet, List<TreeNode> result) {
if (node == null) return null;
node.left = DFS(node.left, deleteSet, result);
node.right = DFS(node.right, deleteSet, result);
if (deleteSet.Contains(node.val)) {
if (node.left != null) result.Add(node.left);
if (node.right != null) result.Add(node.right);
return null;
}
return node;
}
}
var delNodes = function(root, to_delete) {
const deleteSet = new Set(to_delete);
const result = [];
function dfs(node) {
if (!node) return null;
node.left = dfs(node.left);
node.right = dfs(node.right);
if (deleteSet.has(node.val)) {
if (node.left) result.push(node.left);
if (node.right) result.push(node.right);
return null;
}
return node;
}
const newRoot = dfs(root);
if (newRoot) {
result.push(newRoot);
}
return result;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 需要遍历树中的每个节点一次,其中n为节点总数 |
| 空间复杂度 | O(h + m) | h为树的高度(递归栈空间),m为待删除节点数量(哈希表空间) |
相关题目
- . Count Nodes With the Highest Score (Medium)