1
1
2
+ ## 题目链接
3
+
4
+ https://leetcode-cn.com/problems/trim-a-binary-search-tree/
5
+
2
6
> 如果不对递归有深刻的理解,本题有点难
3
7
8
+ > 单纯移除一个节点那还不够,要修剪!
9
+
4
10
# 669. 修剪二叉搜索树
5
11
12
+ 题目链接:https://leetcode-cn.com/problems/trim-a-binary-search-tree/
13
+
6
14
给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[ L, R] 中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。
7
15
8
16
![ 669.修剪二叉搜索树] ( https://img-blog.csdnimg.cn/20201014173115788.png )
11
19
12
20
# 思路
13
21
14
- 相信看到这道题目大家都感觉是一道简单题(事实上leetcode上也表明是简单)。
22
+ 相信看到这道题目大家都感觉是一道简单题(事实上leetcode上也标明是简单)。
23
+
24
+ 但还真的不简单!
15
25
16
26
## 递归法
17
27
18
- 直接想法就是:递归处理,然后遇到 ` root->val < low || root->val > high ` 的时候直接return NULL。一波修建 ,赶紧利落。
28
+ 直接想法就是:递归处理,然后遇到 ` root->val < low || root->val > high ` 的时候直接return NULL,一波修改 ,赶紧利落。
19
29
20
30
不难写出如下代码:
21
31
@@ -31,7 +41,7 @@ public:
31
41
};
32
42
```
33
43
34
- ** 然而[ 1, 3] 区间在二叉搜索树的中可不是单纯的节点3和左孩子节点0就决定的,还要考虑节点0的右子树。 **
44
+ ** 然而[ 1, 3] 区间在二叉搜索树的中可不是单纯的节点3和左孩子节点0就决定的,还要考虑节点0的右子树** 。
35
45
36
46
我们在重新关注一下第二个示例,如图:
37
47
@@ -43,7 +53,7 @@ public:
43
53
44
54
其实不用重构那么复杂。
45
55
46
- 在上图中我们发现节点0并不符合区间要求,那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了(就是把元素0减掉 ),如图:
56
+ 在上图中我们发现节点0并不符合区间要求,那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了(就是把节点0从二叉树中移除 ),如图:
47
57
48
58
<img src =' ../pics/669.修剪二叉搜索树1.png ' width =600 > </img ></div >
49
59
@@ -52,14 +62,13 @@ public:
52
62
53
63
* 确定递归函数的参数以及返回值
54
64
55
- 首先 ** 我们要返回函数参数节点(root)为根节点的树 修剪完之后的 新的根节点 ** , 这里我们为什么需要返回值呢?
65
+ 这里我们为什么需要返回值呢?
56
66
67
+ 因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。
57
68
58
- 因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是要删除节点)的操作 。
69
+ 但是有返回值,更方便,可以通过递归函数的返回值来移除节点 。
59
70
60
- 但是有返回值,更方便,可以通过 这样的赋值语句:` root->left = trimBST(root->left, int low, int high) ` 直接删除root的左孩子(如果root的左孩子不在范围内的话)。
61
-
62
- ** 因为` trimBST(root->left, int low, int high) ` 将返回当前root左子树(以root->left为根节点的二叉树)修剪完之后的新的根节点。**
71
+ 这样的做法在[ 二叉树:搜索树中的插入操作] ( https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA ) 和[ 二叉树:搜索树中的删除操作] ( https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw ) 中大家已经了解过了。
63
72
64
73
代码如下:
65
74
@@ -77,7 +86,7 @@ if (root == nullptr ) return nullptr;
77
86
78
87
* 确定单层递归的逻辑
79
88
80
- 如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树的头结点 。
89
+ 如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点 。
81
90
82
91
代码如下:
83
92
@@ -88,7 +97,7 @@ if (root->val < low) {
88
97
}
89
98
```
90
99
91
- 如果root(当前节点)的元素小于high的,那么应该递归左子树,并返回左子树的头结点 。
100
+ 如果root(当前节点)的元素小于high的,那么应该递归左子树,并返回左子树符合条件的头结点 。
92
101
93
102
代码如下:
94
103
@@ -99,33 +108,43 @@ if (root->val > high) {
99
108
}
100
109
```
101
110
102
- 接下来要将处理完左子树的结果赋给root ->left,处理完右子树的结果赋给root->right。
111
+ 接下来要将下一层处理完左子树的结果赋给root ->left,处理完右子树的结果赋给root->right。
103
112
104
113
最后返回root节点,代码如下:
105
114
106
-
107
115
```
108
116
root->left = trimBST(root->left, low, high); // root->left接入符合条件的左孩子
109
117
root->right = trimBST(root->right, low, high); // root->right接入符合条件的右孩子
110
118
return root;
111
119
```
112
120
113
- 此时大家是不是还没发现这个 多余的节点究竟是如何删除的?
121
+ 此时大家是不是还没发现这多余的节点究竟是如何从二叉树中移除的呢?
122
+
123
+ 在回顾一下上面的代码,针对下图中二叉树的情况:
124
+
125
+ <img src =' ../pics/669.修剪二叉搜索树1.png ' width =600 > </img ></div >
126
+
127
+ 如下代码相当于把节点0的右孩子(节点2)返回给上一层,
128
+ ```
129
+ if (root->val < low) {
130
+ TreeNode* right = trimBST(root->right, low, high); // 寻找符合区间[low, high]的节点
131
+ return right;
132
+ }
133
+ ```
134
+
135
+ 然后如下代码相当于用节点3的左孩子 把下一层返回的 节点0的右孩子(节点2) 接住。
114
136
115
- 其实就是通过,这两个语句删除的。
116
137
```
117
138
root->left = trimBST(root->left, low, high);
118
- root->right = trimBST(root->right, low, high);
119
139
```
120
140
121
- root重新规划root的左右孩子究竟是谁,拿图中示例为例,此时root为节点3,那么trimBST(root->left, low, high)返回的就是节点2, ` root->left = trimBST(root->left, low, high); ` 相当于把节点0删除了 。
141
+ 此时节点3的右孩子就变成了节点2,将节点0从二叉树中移除了 。
122
142
123
143
最后整体代码如下:
124
144
125
145
```
126
146
class Solution {
127
147
public:
128
- // 注意这里是返回该树的头结点
129
148
TreeNode* trimBST(TreeNode* root, int low, int high) {
130
149
if (root == nullptr ) return nullptr;
131
150
if (root->val < low) {
@@ -159,6 +178,8 @@ public:
159
178
};
160
179
```
161
180
181
+ 只看代码,其实不太好理解节点是符合移除的,这一块大家可以自己在模拟模拟!
182
+
162
183
## 迭代法
163
184
164
185
因为二叉搜索树的有序性,不需要使用栈模拟递归的过程。
@@ -212,6 +233,6 @@ public:
212
233
213
234
** 如果不对递归有深刻的理解,这道题目还是有难度的!**
214
235
215
- 本题我依然给出递归法和迭代法,大家只要掌握递归其实就可以了 ,如果想进一步学习,就把迭代法也写一写。
236
+ 本题我依然给出递归法和迭代法,初学者掌握递归就可以了 ,如果想进一步学习,就把迭代法也写一写。
216
237
217
238
** 就酱,如果学到了,就转发给身边需要的同学吧!**
0 commit comments