301.二叉搜索树中的插入操作
给定二叉搜索树(BST)的根节点 root
和要插入树中的值 value
,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
示例 1:
输入:root = [4,2,7,1,3], val = 5 输出:[4,2,7,1,3,5] 解释:另一个满足题目要求可以通过的树是:
示例 2:
输入:root = [40,20,60,10,30,50,70], val = 25 输出:[40,20,60,10,30,50,70,null,null,25]
示例 3:
输入:root = [4,2,7,1,3,null,null,null,null,null,null], val = 5 输出:[4,2,7,1,3,5]
提示:
- 树中的节点数将在
[0, 104]
的范围内。 -108 <= Node.val <= 108
- 所有值
Node.val
是 独一无二 的。 -108 <= val <= 108
- 保证
val
在原始BST中不存在。
思路
写了半天思路没有打开,以为需要考虑加在已连接的两个节点中间的情况,但是实际上任何时候都可以找到一个没有左子树或者右子树的节点直接插入,不需要多余的操作,这样思路就简单多了。
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if (root == null) {
return new TreeNode(val);
}
Stack<TreeNode> stack=new Stack<>();
TreeNode pos=root;
while(pos!=null){
if (val < pos.val) {
if(pos.left==null){
pos.left=new TreeNode(val);
break;
}else {
pos=pos.left;
}
}else {
if (pos.right == null) {
pos.right=new TreeNode(val);
break;
}else{
pos=pos.right;
}
}
}
return root;
}
}
这里有一个需要注意的点就是当树为空时需要将新节点当作根节点返回。
450.删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
- 首先找到需要删除的节点;
- 如果找到了,删除它。
示例 1:
输入:root = [5,3,6,2,4,null,7], key = 3 输出:[5,4,6,2,null,null,7] 解释:给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。 一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。 另一个正确答案是 [5,2,6,null,4,null,7]。
示例 2:
输入: root = [5,3,6,2,4,null,7], key = 0 输出: [5,3,6,2,4,null,7] 解释: 二叉树不包含值为 0 的节点
示例 3:
输入: root = [], key = 0 输出: []
提示:
- 节点数的范围
[0, 104]
. -105 <= Node.val <= 105
- 节点值唯一
root
是合法的二叉搜索树-105 <= key <= 105
进阶: 要求算法时间复杂度为 O(h),h 为树的高度。
思路
删除一个节点分为两种情况:
1、删除的节点为叶子节点,此时只要简单删除该节点即可,将父节点的对应子节点删除。
2、若删除的节点有子树,也分为两种情况:
a、删除节点只有一个儿子,则将该子节点代替删除节点的位置。
b、删除节点有两个子节点。此时需要将其中一个节点上移,另一个节点作为该节点的子节点,但是若上移节点有两个子树,此时需要将其中一个子树移动到另一个节点所在子树中。
我们假设将右节点b上移,那么左节点a就会变成b的左子节点,此时b的原左子树需要移动到a所在子树,根据二叉搜索树的特点,b的原左子树一定大于a所在子树中所有值,所以将其移动到a所在子树的最右节点的右子树。
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root==null){
return null;
}
if(key>root.val){
root.right=deleteNode(root.right,key);
}else if(key<root.val){
root.left=deleteNode(root.left,key);
}else{
if(root.left==null){
root=root.right;
}else if(root.right==null){
root=root.left;
}else{
TreeNode tmp=root.left;
while(tmp.right!=null){
tmp=tmp.right;
}
tmp.right=root.right.left;
root.right.left=root.left;
root=root.right;
}
}
return root;
}
}
还得是递归,迭代真拎不清。
迭代法
其实迭代法的思路也很简单,设置一个父节点记录一下即可,其他思路一样
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
TreeNode cur=root,par=null;
while(cur!=null&&cur.val!=key){
par=cur;
if (cur.val > key) {
cur=cur.left;
}else {
cur=cur.right;
}
}
if (cur == null) {
return root;
}
if (cur.left == null) {
cur=cur.right;
}else if(cur.right==null){
cur=cur.left;
}else {
TreeNode tmp=cur.left;
while(tmp.right!=null){
tmp=tmp.right;
}
tmp.right=cur.right.left;
cur.right.left=cur.left;
cur=cur.right;
}
if (par == null) {
return cur;
}else{
if(par.left!=null&&par.left.val==key){
par.left=cur;
}else {
par.right=cur;
}
}
return root;
}
}
总结
今天的题目先把思路写出来再去写的代码,感觉流畅了很多。