Skip to content

Commit 448ccf4

Browse files
committed
add LeetCode 450. 删除二叉搜索树中的节点
1 parent 22c68f4 commit 448ccf4

File tree

1 file changed

+199
-0
lines changed

1 file changed

+199
-0
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL2Nob2NvbGF0ZTE5OTkvY2RuL2ltZy8yMDIwMDgyODE0NTUyMS5qcGc?x-oss-process=image/format,png)
2+
>仰望星空的人,不应该被嘲笑
3+
4+
## 题目描述
5+
给定一个二叉搜索树的根节点 **root** 和一个值 **key**,删除二叉搜索树中的 **key** 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
6+
7+
一般来说,删除节点可分为两个步骤:
8+
9+
首先找到需要删除的节点;
10+
如果找到了,删除它。
11+
说明: 要求算法时间复杂度为 O(h),h 为树的高度。
12+
13+
示例:
14+
15+
```javascript
16+
root = [5,3,6,2,4,null,7]
17+
key = 3
18+
19+
5
20+
/ \
21+
3 6
22+
/ \ \
23+
2 4 7
24+
25+
给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。
26+
27+
一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。
28+
29+
5
30+
/ \
31+
4 6
32+
/ \
33+
2 7
34+
35+
另一个正确答案是 [5,2,6,null,4,null,7]。
36+
37+
5
38+
/ \
39+
2 6
40+
\ \
41+
4 7
42+
```
43+
44+
来源:力扣(LeetCode)
45+
链接:https://leetcode-cn.com/problems/delete-node-in-a-bst
46+
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
47+
48+
49+
50+
51+
## 解题思路
52+
对于这道题,我们必须先了解一下二叉搜索树(BST)的性质,如下:
53+
54+
BST性质
55+
- 中序遍历是升序
56+
- left小于当前节点,right大于当前节点
57+
- 左子树、右子树也要是BST
58+
59+
60+
了解了性质之后,我们知道要查找对应 `key` 值,可以与根节点进行比较,如果小于根节点,直接去左子树找就好了,如果大于根节点,直接去右子树找就好了。
61+
62+
而对于刚好等于根节点的话,我拿着大佬的图解来看看几种情况:
63+
64+
65+
第一种情况,如果删除节点仅有右孩子,直接指向右孩子
66+
![](https://img-blog.csdnimg.cn/20200924222416522.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjQyOTcxOA==,size_16,color_FFFFFF,t_70#pic_center)
67+
第二种情况,如果删除节点仅有左孩子,直接指向左孩子
68+
![](https://img-blog.csdnimg.cn/2020092422242489.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjQyOTcxOA==,size_16,color_FFFFFF,t_70#pic_center)
69+
第三种情况,如果删除节点左右孩子都有,那么我们按照题意可以有两种删除方法:
70+
71+
① 找到要删除节点左子树的最右边的节点,即前驱的最大值(由BST性质得到)替换当前 root 节点,然后删除这个前驱
72+
73+
② 找到要删除节点右子树的最左边的节点,即后继最小值(由BST性质得到)替换当前 root 节点,然后删除这个后继
74+
![](https://img-blog.csdnimg.cn/20200924222430454.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjQyOTcxOA==,size_16,color_FFFFFF,t_70#pic_center)
75+
76+
77+
78+
参考 <a href="https://leetcode-cn.com/problems/delete-node-in-a-bst/solution/tu-jie-di-gui-shi-xian-shan-chu-bstzhong-de-jie-di/">lulua> 大佬图解
79+
80+
代码提供了两种解法,对于前两种情况处理是一样的,只是对于最后一种情况,可以删除前驱的最大值,或者删除后继的最小值。
81+
82+
**删除前驱的最大值代码**
83+
84+
```javascript
85+
/**
86+
* Definition for a binary tree node.
87+
* function TreeNode(val, left, right) {
88+
* this.val = (val===undefined ? 0 : val)
89+
* this.left = (left===undefined ? null : left)
90+
* this.right = (right===undefined ? null : right)
91+
* }
92+
*/
93+
/**
94+
* @param {TreeNode} root
95+
* @param {number} key
96+
* @return {TreeNode}
97+
*/
98+
var deleteNode = function (root, key) {
99+
if (!root) return null;
100+
// 判断值是否小于root,小于走左子树,大于走右子树
101+
if (key < root.val) {
102+
root.left = deleteNode(root.left, key);
103+
} else if (key > root.val) {
104+
root.right = deleteNode(root.right, key);
105+
} else {
106+
// 1.如果删除节点没有左右子树,直接删除即可
107+
if (!root.left && !root.right) {
108+
root = null;
109+
// 2.如果删除节点仅有左孩子,直接指向左孩子
110+
} else if (root.left && !root.right) {
111+
root = root.left;
112+
// 3.如果删除节点仅有右孩子,直接指向右孩子
113+
} else if (!root.left && root.right) {
114+
root = root.right;
115+
} else {
116+
// 4.如果左右孩子都有,本代码采用方式是将前驱的最大值替换root的值
117+
let last = root.left;
118+
while (last.right) {
119+
last = last.right;
120+
}
121+
root.val = last.val;
122+
// 然后删除这个前驱最大值节点即可
123+
root.left = deleteNode(root.left, last.val);
124+
}
125+
}
126+
return root;
127+
};
128+
```
129+
130+
131+
**删除后继的最小值代码**
132+
133+
```javascript
134+
/**
135+
* Definition for a binary tree node.
136+
* function TreeNode(val, left, right) {
137+
* this.val = (val===undefined ? 0 : val)
138+
* this.left = (left===undefined ? null : left)
139+
* this.right = (right===undefined ? null : right)
140+
* }
141+
*/
142+
/**
143+
* @param {TreeNode} root
144+
* @param {number} key
145+
* @return {TreeNode}
146+
*/
147+
var deleteNode = function (root, key) {
148+
if (!root) return null;
149+
// 判断值是否小于root,小于走左子树,大于走右子树
150+
if (key < root.val) {
151+
root.left = deleteNode(root.left, key);
152+
} else if (key > root.val) {
153+
root.right = deleteNode(root.right, key);
154+
} else {
155+
// 1.如果删除节点没有左右子树,直接删除即可
156+
if (!root.left && !root.right) {
157+
root = null;
158+
// 2.如果删除节点仅有左孩子,直接指向左孩子
159+
} else if (root.left && !root.right) {
160+
root = root.left;
161+
// 3.如果删除节点仅有右孩子,直接指向右孩子
162+
} else if (!root.left && root.right) {
163+
root = root.right;
164+
} else {
165+
// 4.如果左右孩子都有,本代码采用方式是将后继的最小值替换root的值
166+
let last = root.right;
167+
while (last.left) {
168+
last = last.left;
169+
}
170+
root.val = last.val;
171+
// 然后删除这个后继最小值节点即可
172+
root.right = deleteNode(root.right, last.val);
173+
}
174+
}
175+
return root;
176+
};
177+
```
178+
179+
## 最后
180+
文章产出不易,还望各位小伙伴们支持一波!
181+
182+
往期精选:
183+
184+
<a href="https://github.com/Chocolate1999/Front-end-learning-to-organize-notes">小狮子前端の笔记仓库a>
185+
186+
<a href="https://github.com/Chocolate1999/leetcode-javascript">leetcode-javascript:LeetCode 力扣的 JavaScript 解题仓库,前端刷题路线(思维导图)a>
187+
188+
小伙伴们可以在Issues中提交自己的解题代码,🤝 欢迎Contributing,可打卡刷题,Give a ⭐️ if this project helped you!
189+
190+
191+
<a href="https://yangchaoyi.vip/">访问超逸の博客a>,方便小伙伴阅读玩耍~
192+
193+
![](https://img-blog.csdnimg.cn/2020090211491121.png#pic_center)
194+
195+
```javascript
196+
学如逆水行舟,不进则退
197+
```
198+
199+

0 commit comments

Comments
 (0)