Skip to content

Commit d1e62bb

Browse files
committedJul 17, 2024
1110. Delete Nodes And Return Forest
1 parent 5e1dd47 commit d1e62bb

File tree

10 files changed

+363
-0
lines changed

10 files changed

+363
-0
lines changed
 
Loading
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* Definition for a binary tree node.
3+
* struct TreeNode {
4+
* int val;
5+
* TreeNode *left;
6+
* TreeNode *right;
7+
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
8+
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
9+
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left),
10+
* right(right) {}
11+
* };
12+
*/
13+
class Solution
14+
{
15+
public:
16+
// Fonction pour supprimer un noeud et ajuster l'arbre en conséquence
17+
void deleteNode(TreeNode *parent, TreeNode *child, bool isLeft, vector<TreeNode *> &ans,
18+
unordered_set<int> &toDelete)
19+
{
20+
toDelete.erase(child->val); // Supprimer le noeud du set toDelete
21+
22+
// Ajouter les enfants du noeud supprimé à la liste des résultats
23+
if (child->left)
24+
{
25+
ans.push_back(child->left);
26+
}
27+
if (child->right)
28+
{
29+
ans.push_back(child->right);
30+
}
31+
32+
// Détacher le noeud supprimé de son parent
33+
if (isLeft)
34+
{
35+
parent->left = nullptr;
36+
}
37+
else
38+
{
39+
parent->right = nullptr;
40+
}
41+
42+
// Libérer la mémoire des noeuds supprimés
43+
// delete child;
44+
}
45+
46+
// Fonction DFS pour explorer et marquer les noeuds à supprimer
47+
bool dfs(TreeNode *root, vector<TreeNode *> &ans, unordered_set<int> &toDelete)
48+
{
49+
if (root->left && dfs(root->left, ans, toDelete))
50+
{
51+
deleteNode(root, root->left, true, ans, toDelete);
52+
}
53+
if (root->right && dfs(root->right, ans, toDelete))
54+
{
55+
deleteNode(root, root->right, false, ans, toDelete);
56+
}
57+
58+
// Retourne true si le noeud actuel doit être supprimé
59+
return toDelete.find(root->val) != toDelete.end();
60+
}
61+
62+
vector<TreeNode *> delNodes(TreeNode *root, vector<int> &to_delete)
63+
{
64+
vector<TreeNode *> ans;
65+
unordered_set<int> toDelete(to_delete.begin(), to_delete.end());
66+
67+
// Si la racine doit être supprimée, ajouter ses enfants à la liste des résultats
68+
if (dfs(root, ans, toDelete))
69+
{
70+
if (root->left)
71+
{
72+
ans.push_back(root->left);
73+
}
74+
if (root->right)
75+
{
76+
ans.push_back(root->right);
77+
}
78+
79+
// Libérer la mémoire des noeuds supprimés
80+
// delete root;
81+
}
82+
// Sinon, ajouter la racine à la liste des résultats
83+
else
84+
{
85+
ans.push_back(root);
86+
}
87+
88+
// Retourner les racines des sous-arbres restants
89+
return ans;
90+
}
91+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
# 1110. Delete Nodes And Return Forest
2+
3+
## Énoncé
4+
5+
Étant donné la racine `root` d'un arbre binaire, chaque noeud de l'arbre a une valeur distincte.
6+
7+
Après avoir supprimé tous les noeuds avec une valeur dans `to_delete`, il nous reste une forêt (une union disjointe d'arbres).
8+
9+
Retournez les racines des arbres dans la forêt restante. Vous pouvez retourner le résultat dans n'importe quel ordre.
10+
11+
## Exemple
12+
13+
**Exemple 1:**
14+
15+
<img src="./imgs/img1.png" width="237px" height="150px"/>
16+
17+
**Input:** root = [1,2,3,4,5,6,7], to_delete = [3,5]
18+
**Output:** [[1,2,null,4],[6],[7]]
19+
20+
**Exemple 2:**
21+
**Input:** root = [1,2,4,null,3], to_delete = [3]
22+
**Output:** [[1,2,4]]
23+
24+
## Contraintes
25+
26+
Le nombre de noeuds dans l'arbre donné est au maximum de `1000`
27+
Chaque noeud a une valeur distincte entre `1` et `1000`
28+
`to_delete.length <= 1000`
29+
`to_delete` contient des valeurs distinctes entre `1` et `1000`
30+
31+
## Note personnelle
32+
33+
Dans chaque approche proposée, une partie du code est commentée, celui-ci permet de libérer la mémoire des noeuds supprimés pour éviter les fuites de mémoires.
34+
35+
### Approche 1: Trouver et Supprimer les Éléments dans les Forêts
36+
37+
Cette approche consiste à stocker les racines des forêts dans un ensemble `unordered_set`. Pour chaque élément à supprimer, nous effectuons une recherche en profondeur (DFS) dans chaque forêt jusqu'à trouver l'élément à supprimer. À chaque suppression, nous créons les forêts résultantes que nous ajoutons à l'ensemble.
38+
39+
```cpp
40+
// Fonction DFS pour trouver le noeud et son parent
41+
pair<TreeNode*, TreeNode*> dfs(TreeNode* root, int value){
42+
// Si la racine est le noeud recherché
43+
if(root->val == value){
44+
return {nullptr, root};
45+
}
46+
47+
stack<TreeNode*> sta;
48+
sta.push(root);
49+
50+
while(!sta.empty()){
51+
TreeNode* curr = sta.top();
52+
sta.pop();
53+
54+
// Vérification du sous-arbre gauche
55+
if(curr->left){
56+
if(curr->left->val == value){
57+
return {curr, curr->left};
58+
}
59+
sta.push(curr->left);
60+
}
61+
// Vérification du sous-arbre droit
62+
if(curr->right){
63+
if(curr->right->val == value){
64+
return {curr, curr->right};
65+
}
66+
sta.push(curr->right);
67+
}
68+
}
69+
70+
// Si le noeud avec la valeur donnée n'est pas trouvé
71+
return {nullptr, nullptr};
72+
}
73+
74+
vector<TreeNode*> delNodes(TreeNode* root, vector<int>& to_delete) {
75+
unordered_set<TreeNode*> forests;
76+
forests.insert(root); // Initialiser la forêt avec la racine
77+
78+
// Parcours de chaque élément a supprimé
79+
for(int element : to_delete){
80+
// Parcours de chaque forêt
81+
for(TreeNode* f : forests){
82+
pair<TreeNode*, TreeNode*> r = dfs(f, element);
83+
84+
// Si le noeud à supprimer n'est pas trouvé
85+
if(!r.second){
86+
continue;
87+
}
88+
89+
// Si le noeud à supprimer est la racine
90+
if(!r.first){
91+
forests.erase(r.second);
92+
}
93+
else{
94+
// Détache le noeud à supprimer de son parent
95+
if(r.first->left == r.second){
96+
r.first->left = nullptr;
97+
}
98+
else if(r.first->right == r.second){
99+
r.first->right = nullptr;
100+
}
101+
}
102+
103+
// Ajouter les sous-arbres du noeud supprimé à la forêt
104+
if(r.second->left){
105+
forests.insert(r.second->left);
106+
}
107+
if(r.second->right){
108+
forests.insert(r.second->right);
109+
}
110+
111+
// Libérer la mémoire du noeud supprimé
112+
// delete r.second;
113+
114+
break;
115+
}
116+
}
117+
118+
// Retourner les racines des sous-arbres restants
119+
return vector<TreeNode*>(forests.begin(), forests.end());
120+
}
121+
```
122+
123+
- Complexité Temporelle: `O(n * m)`
124+
- Complexité Spatiale: `O(m + h)`
125+
- `n` est le nombre de noeuds dans l'arbre, `m` est le nombre d'éléments à supprimer, et `h` est la hauteur de l'arbre.
126+
127+
### Approche 2: Utiliser une HashMap pour Stocker les Éléments et Procéder à la Suppression
128+
129+
Cette approche consiste à stocker chaque noeud et son parent dans une HashMap avec la valeur du noeud comme clé, permettant une recherche efficace de l'élément à supprimer. La gestion des forêts reste la même que dans l'approche précédente.
130+
131+
```cpp
132+
// Fonction DFS pour remplir la map avec les noeuds et leurs parents
133+
void dfs(TreeNode* root, unordered_map<int, pair<TreeNode*, TreeNode*>> &mp){
134+
if(root->left){
135+
mp[root->left->val] = {root, root->left}; // Ajouter le noeud gauche et son parent
136+
dfs(root->left, mp); // Appel récursif sur le noeud gauche
137+
}
138+
if(root->right){
139+
mp[root->right->val] = {root, root->right}; // Ajouter le noeud droit et son parent
140+
dfs(root->right, mp); // Appel récursif sur le noeud droit
141+
}
142+
}
143+
144+
vector<TreeNode*> delNodes(TreeNode* root, vector<int>& to_delete) {
145+
unordered_map<int, pair<TreeNode*, TreeNode*>> mp; // Map pour stocker les noeuds et leurs parents
146+
unordered_set<TreeNode*> set; // Ensemble pour stocker les racines des sous-arbres
147+
148+
mp[root->val] = {nullptr, root}; // La racine n'a pas de parent
149+
set.insert(root); // Ajouter la racine à l'ensemble
150+
151+
dfs(root, mp); // Remplir la map avec les noeuds de l'arbre
152+
153+
// Traiter chaque élément à supprimer
154+
for(int element: to_delete){
155+
pair<TreeNode*, TreeNode*> curr = mp[element];
156+
157+
// Détache le noeud à supprimer de son parent
158+
if(curr.first){
159+
if(curr.first->left == curr.second){
160+
curr.first->left = nullptr;
161+
}
162+
else if(curr.first->right == curr.second){
163+
curr.first->right = nullptr;
164+
}
165+
}
166+
167+
set.erase(curr.second); // Retire le noeud à supprimer de l'ensemble
168+
169+
// Ajouter les sous-arbres du noeud supprimé à l'ensemble
170+
if(curr.second->left){
171+
set.insert(curr.second->left);
172+
}
173+
if(curr.second->right){
174+
set.insert(curr.second->right);
175+
}
176+
}
177+
178+
// Libérer la mémoire des noeuds supprimés
179+
// for(int element: to_delete){
180+
// delete mp[element].second;
181+
// }
182+
183+
// Retourner les racines des sous-arbres restants
184+
return vector<TreeNode*>(set.begin(), set.end());
185+
}
186+
```
187+
188+
- Complexité Temporelle: `O(n + m)`
189+
- Complexité Spatiale: `O(n + m + h)`
190+
- `n` est le nombre de noeuds dans l'arbre, `m` est le nombre d'éléments à supprimer, et `h` est la hauteur de l'arbre.
191+
192+
### Approche 3: Parcourir l'Arbre et Supprimer les Éléments Simultanément
193+
194+
Cette approche parcourt l'arbre en profondeur tout en supprimant les éléments.
195+
196+
Chaque itération retourne `true` ou `false`pour indiquer si le noeud enfant concerné doit être supprimé ou non. La liste `to_delete` est convertie en un ensemble `unrodered_set` pour faciliter la vérification.
197+
198+
```cpp
199+
// Fonction pour supprimer un noeud et ajuster l'arbre en conséquence
200+
void deleteNode(TreeNode* parent, TreeNode* child, bool isLeft, vector<TreeNode*> &ans, unordered_set<int> &toDelete){
201+
toDelete.erase(child->val); // Supprimer le noeud du set toDelete
202+
203+
// Ajouter les enfants du noeud supprimé à la liste des résultats
204+
if(child->left){
205+
ans.push_back(child->left);
206+
}
207+
if(child->right){
208+
ans.push_back(child->right);
209+
}
210+
211+
// Détacher le noeud supprimé de son parent
212+
if(isLeft){
213+
parent->left = nullptr;
214+
}
215+
else{
216+
parent->right = nullptr;
217+
}
218+
219+
// Libérer la mémoire des noeuds supprimés
220+
// delete child;
221+
}
222+
223+
// Fonction DFS pour explorer et marquer les noeuds à supprimer
224+
bool dfs(TreeNode* root, vector<TreeNode*> &ans, unordered_set<int> &toDelete){
225+
if(root->left && dfs(root->left, ans, toDelete)){
226+
deleteNode(root, root->left, true, ans, toDelete);
227+
}
228+
if(root->right && dfs(root->right, ans, toDelete)){
229+
deleteNode(root, root->right, false, ans, toDelete);
230+
}
231+
232+
// Retourne true si le noeud actuel doit être supprimé
233+
return toDelete.find(root->val) != toDelete.end();
234+
}
235+
236+
vector<TreeNode*> delNodes(TreeNode* root, vector<int>& to_delete) {
237+
vector<TreeNode*> ans;
238+
unordered_set<int> toDelete(to_delete.begin(), to_delete.end());
239+
240+
// Si la racine doit être supprimée, ajouter ses enfants à la liste des résultats
241+
if(dfs(root, ans, toDelete)){
242+
if(root->left){
243+
ans.push_back(root->left);
244+
}
245+
if(root->right){
246+
ans.push_back(root->right);
247+
}
248+
249+
// Libérer la mémoire des noeuds supprimés
250+
// delete root;
251+
}
252+
// Sinon, ajouter la racine à la liste des résultats
253+
else{
254+
ans.push_back(root);
255+
}
256+
257+
// Retourner les racines des sous-arbres restants
258+
return ans;
259+
}
260+
```
261+
262+
- Complexité Temporelle: `O(n + m)`
263+
- Complexité Spatiale: `O(m + h)`
264+
- `n` est le nombre de noeuds dans l'arbre, `m` est le nombre d'éléments à supprimer, et `h` est la hauteur de l'arbre.
265+
266+
<img src="./imgs/runtime.png"/>
267+
<img src="./imgs/memory.png"/>

‎skills/array.md

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ Illustration d'un tableau a une dimension:
9393
| [934. Shortest Bridge](../Probleme/0934.%20Shortest%20Bridge/) | [`Array`](./array.md), [`Depth-First Search`](./dfs.md), [`Breadth-First Search`](./bfs.md), [`Matrix`](./matrix.md) | 29-03-2024 |
9494
| [948. Bag of Tokens](../Probleme/0948.%20Bag%20of%20Tokens/) | [`Array`](./array.md), [`Greedy`](./greedy.md), [`Two Pointers`](./two_pointers.md), [`Sorting`](./sorting.md) | 04-03-2024 |
9595
| [1052. Grumpy Bookstore Owner](../Probleme/1052.%20Grumpy%20Bookstore%20Owner/) | [`Array`](./array.md), [`Sliding Window`](./sliding_window.md) | 22-06-2024 |
96+
| [1110. Delete Nodes And Return Forest](../Probleme/1110.%20Delete%20Nodes%20And%20Return%20Forest/) | [`Array`](./array.md), [`Hash Table`](./hash_table.md), [`Tree`](./tree.md), [`Depth-First Search`](./dfs.md), [`Binary Tree`](./binary_tree.md) | 17-07-2024 |
9697
| [1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit](../Probleme/1438.%20Longest%20Continuous%20Subarray%20With%20Absolute%20Diff%20Less%20Than%20or%20Equal%20to%20Limit/) | [`Array`](./array.md), [`Queue`](./queue.md), [`Sliding Window`](./sliding_window.md), [`Heap (Priority Queue)`](./priority_queue.md), [`Ordered Set`](./ordered_set.md), [`Monotonic Queue`](./monotonic_queue.md) | 23-06-2024 |
9798
| [1679. Max Number of K-Sum Pairs](../Probleme/1679.%20Max%20Number%20of%20K-Sum%20Pairs/) | [`Array`](./array.md), [`Two Pointers`](./two_pointers.md), [`Sorting`](./sorting.md), [`Hash Table`](./hash_table.md) | 13-03-2024 |
9899
| [1701. Average Waiting Time](../Probleme/1701.%20Average%20Waiting%20Time/) | [`Array`](./array.md), [`Simulation`](./simulation.md) | 09-07-2024 |

‎skills/binary_tree.md

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Un exemple simple d'arbre binaire:
2929
| [623. Add One Row to Tree](../Probleme/0623.%20Add%20One%20Row%20to%20Tree/) | [`Tree`](./tree.md), [`Depth-First Search`](./dfs.md), [`Breadth-First Search`](./bfs.md), [`Binary Tree`](./binary_tree.md) | 16-04-2024 |
3030
| [988. Smallest String Starting From Leaf](../Probleme/0988.%20Smallest%20String%20Starting%20From%20Leaf/) | [`String`](./string.md), [`Tree`](./tree.md), [`Depth-First Search`](./dfs.md), [`Binary Tree`](./binary_tree.md) | 17-01-2024 |
3131
| [1038. Binary Search Tree to Greater Sum Tree](../Probleme/1038.%20Binary%20Search%20Tree%20to%20Greater%20Sum%20Tree/) | [`Tree`](./tree.md), [`Depth-First Search`](./dfs.md), [`Binary Search Tree`](./binary_search_tree.md), [`Binary Tree`](./binary_tree.md) | 25-06-2024 |
32+
| [1110. Delete Nodes And Return Forest](../Probleme/1110.%20Delete%20Nodes%20And%20Return%20Forest/) | [`Array`](./array.md), [`Hash Table`](./hash_table.md), [`Tree`](./tree.md), [`Depth-First Search`](./dfs.md), [`Binary Tree`](./binary_tree.md) | 17-07-2024 |
3233
| [1382. Balance a Binary Search Tree](../Probleme/1382.%20Balance%20a%20Binary%20Search%20Tree/) | [`Divide and Conquer`](./divide_and_conquer.md), [`Greedy`](./greedy.md), [`Tree`](./tree.md), [`Depth-First Search`](./dfs.md), [`Binary Search Tree`](./binary_search_tree.md), [`Binary Tree`](./binary_tree.md) | 26-06-2024 |
3334
| [1609. Even Odd Tree](../Probleme/1609.%20Even%20Odd%20Tree/) | [`Tree`](./tree.md), [`Breadth-First Search`](./bfs.md), [`Binary Tree`](./binary_tree.md) | 29-02-2024 |
3435
| [2196. Create Binary Tree From Descriptions](../Probleme/2196.%20Create%20Binary%20Tree%20From%20Descriptions/) | [`Array`](./array.md), [`Hash Table`](./hash_table.md), [`Tree`](./tree.md), [`Binary Tree`](./binary_tree.md) | 15-07-2024 |

‎skills/dfs.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Exemple animé de l'algorithme de parcours en profondeur:
3232
| [934. Shortest Bridge](../Probleme/0934.%20Shortest%20Bridge/) | [`Array`](./array.md), [`Depth-First Search`](./dfs.md), [`Breadth-First Search`](./bfs.md), [`Matrix`](./matrix.md) | 29-03-2024 |
3333
| [988. Smallest String Starting From Leaf](../Probleme/0988.%20Smallest%20String%20Starting%20From%20Leaf/) | [`String`](./string.md), [`Tree`](./tree.md), [`Depth-First Search`](./dfs.md), [`Binary Tree`](./binary_tree.md) | 17-01-2024 |
3434
| [1038. Binary Search Tree to Greater Sum Tree](../Probleme/1038.%20Binary%20Search%20Tree%20to%20Greater%20Sum%20Tree/) | [`Tree`](./tree.md), [`Depth-First Search`](./dfs.md), [`Binary Search Tree`](./binary_search_tree.md), [`Binary Tree`](./binary_tree.md) | 25-06-2024 |
35+
| [1110. Delete Nodes And Return Forest](../Probleme/1110.%20Delete%20Nodes%20And%20Return%20Forest/) | [`Array`](./array.md), [`Hash Table`](./hash_table.md), [`Tree`](./tree.md), [`Depth-First Search`](./dfs.md), [`Binary Tree`](./binary_tree.md) | 17-07-2024 |
3536
| [1382. Balance a Binary Search Tree](../Probleme/1382.%20Balance%20a%20Binary%20Search%20Tree/) | [`Divide and Conquer`](./divide_and_conquer.md), [`Greedy`](./greedy.md), [`Tree`](./tree.md), [`Depth-First Search`](./dfs.md), [`Binary Search Tree`](./binary_search_tree.md), [`Binary Tree`](./binary_tree.md) | 26-06-2024 |
3637

3738
### Difficile

0 commit comments

Comments
 (0)
Please sign in to comment.