leecode更新
This commit is contained in:
parent
2266507c27
commit
1028801e76
|
|
@ -0,0 +1,254 @@
|
|||
package com.markilue.leecode.tree;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.markilue.leecode.tree.InorderTraversal.inorderTraversal1;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.tree
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-10-08 09:22
|
||||
* @Description: TODO leecode 450题 删除二叉搜索树中的节点:
|
||||
* 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的key对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
|
||||
* 一般来说,删除节点可分为两个步骤:
|
||||
* 1)首先找到需要删除的节点;
|
||||
* 2)如果找到了,删除它。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class DeleteNodeII {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
TreeNode root = new TreeNode(4);
|
||||
TreeNode TreeNode2 = new TreeNode(2);
|
||||
TreeNode TreeNode3 = new TreeNode(6);
|
||||
TreeNode TreeNode4 = new TreeNode(1);
|
||||
TreeNode TreeNode5 = new TreeNode(3);
|
||||
TreeNode TreeNode6 = new TreeNode(5);
|
||||
|
||||
root.setLeft(TreeNode2);
|
||||
root.setRight(TreeNode3);
|
||||
TreeNode2.setLeft(TreeNode4);
|
||||
TreeNode2.setRight(TreeNode5);
|
||||
TreeNode3.setLeft(TreeNode6);
|
||||
|
||||
deleteNode1(root, 5);
|
||||
|
||||
List<Integer> integers = inorderTraversal1(root);
|
||||
|
||||
System.out.println(integers);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test1(){
|
||||
TreeNode root = new TreeNode(5);
|
||||
TreeNode TreeNode2 = new TreeNode(3);
|
||||
TreeNode TreeNode3 = new TreeNode(6);
|
||||
TreeNode TreeNode4 = new TreeNode(2);
|
||||
TreeNode TreeNode5 = new TreeNode(4);
|
||||
TreeNode TreeNode6 = new TreeNode(7);
|
||||
|
||||
root.setLeft(TreeNode2);
|
||||
root.setRight(TreeNode3);
|
||||
TreeNode2.setLeft(TreeNode4);
|
||||
TreeNode2.setRight(TreeNode5);
|
||||
TreeNode3.setRight(TreeNode6);
|
||||
|
||||
deleteNode1(root, 3);
|
||||
|
||||
List<Integer> integers = inorderTraversal1(root);
|
||||
|
||||
System.out.println(integers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 迭代法:找到该节点,然后找到该节点的右子节点的最左节点将其替换,在删除其最左节点
|
||||
* 参考官方迭代法的简洁写法,可以发现官方是使用了child节点记录需要删除的子节点,使得代码统一,同时也避免了两重if
|
||||
* 速度击败100%,内存击败78.04%
|
||||
* @param root
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public TreeNode deleteNode(TreeNode root, int key) {
|
||||
|
||||
//后面的逻辑中包含了这个
|
||||
// if (root == null) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
//TODO 寻找该节点
|
||||
TreeNode temp = root;
|
||||
TreeNode father=null;
|
||||
while (temp != null && temp.val != key) {
|
||||
father=temp;
|
||||
if (temp.val > key) {
|
||||
temp = temp.left;
|
||||
} else {
|
||||
temp = temp.right;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO 判断是什么条件出来的
|
||||
//这里是没找到
|
||||
if(temp==null){
|
||||
return root;
|
||||
}
|
||||
|
||||
TreeNode change=temp; //记录需要改变的这个节点
|
||||
|
||||
//有两个子节点的情况
|
||||
if (temp.right!=null){
|
||||
father=temp;
|
||||
temp=temp.right;
|
||||
|
||||
//寻找该右子节点的最左节点
|
||||
while (temp.left!=null){
|
||||
father=temp;
|
||||
temp=temp.left;
|
||||
}
|
||||
change.val=temp.val; //将最左节点的值赋值给需要改变的节点,接下来删除最左节点
|
||||
change=temp;
|
||||
}
|
||||
|
||||
//删除的是根节点
|
||||
if(father==null){
|
||||
if(temp.left!=null){
|
||||
return temp.left;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//TODO 处理单节点的情况
|
||||
|
||||
//继续删除temp节点,这里要判断他有没有左节点,如果有则是从temp.right!=null出来的
|
||||
if(temp.left!=null){
|
||||
if(father.left==temp){
|
||||
father.left=temp.left;
|
||||
}else {
|
||||
father.right=temp.left;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//继续删除temp节点,这里要判断他有没有有节点,如果有则是进入过temp.right!=null出来的
|
||||
if (temp.right!=null){
|
||||
if(father.left==temp){
|
||||
father.left=temp.right;
|
||||
}else {
|
||||
father.right=temp.right;
|
||||
}
|
||||
}
|
||||
|
||||
//处理叶子节点的情况
|
||||
if(temp.left==null&&temp.right==null){
|
||||
if(father.left==temp){
|
||||
father.left=null;
|
||||
}else {
|
||||
father.right=null;
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 递归法:找到该节点,然后找到该节点的右子节点的最左节点将其替换,在删除其最左节点
|
||||
*
|
||||
* 速度击败100%,内存击败19.68%
|
||||
* @param root
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public TreeNode deleteNode1(TreeNode root, int key) {
|
||||
|
||||
if(root==null)return null;
|
||||
|
||||
if(root.val<key){
|
||||
root.right=deleteNode1(root.right,key);
|
||||
return root;
|
||||
}else if(root.val>key){
|
||||
root.left=deleteNode1(root.left,key);
|
||||
return root;
|
||||
}else {
|
||||
TreeNode result=root;
|
||||
TreeNode father=null;
|
||||
//需要删除的节点
|
||||
if(root.right!=null){
|
||||
father=root;
|
||||
TreeNode temp=root.right;
|
||||
while (temp.left!=null){
|
||||
father=temp;
|
||||
temp=temp.left;
|
||||
}
|
||||
root.val=temp.val;
|
||||
root=temp;
|
||||
}
|
||||
TreeNode child=null;
|
||||
if(root.left!=null)child= root.left;
|
||||
if(root.right!=null)child= root.right;
|
||||
if(father==null) return child;
|
||||
else if(father.left==root)father.left=child;
|
||||
else father.right=child;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方递归法:
|
||||
* @param root
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public TreeNode deleteNode2(TreeNode root, int key) {
|
||||
if (root == null) {
|
||||
return null;
|
||||
}
|
||||
if (root.val > key) {
|
||||
root.left = deleteNode(root.left, key);
|
||||
return root;
|
||||
}
|
||||
if (root.val < key) {
|
||||
root.right = deleteNode(root.right, key);
|
||||
return root;
|
||||
}
|
||||
if (root.val == key) {
|
||||
if (root.left == null && root.right == null) {
|
||||
return null;
|
||||
}
|
||||
if (root.right == null) {
|
||||
return root.left;
|
||||
}
|
||||
if (root.left == null) {
|
||||
return root.right;
|
||||
}
|
||||
TreeNode successor = root.right;
|
||||
while (successor.left != null) {
|
||||
successor = successor.left;
|
||||
}
|
||||
|
||||
//这里删除节点,然后将删完的好节点付给successor并返回(是否可以直接将root的值变为successor的值?)
|
||||
root.right = deleteNode(root.right, successor.val);
|
||||
successor.right = root.right;
|
||||
successor.left = root.left;
|
||||
return successor;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
package com.markilue.leecode.tree;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
import static com.markilue.leecode.tree.InorderTraversal.inorderTraversal1;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.tree
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-10-08 11:45
|
||||
* @Description: TODO 力扣669题 修剪二叉搜索树:
|
||||
* 给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。
|
||||
* 修剪树 不应该改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在唯一的答案。
|
||||
* 所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class TrimBST {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
TreeNode root = new TreeNode(3);
|
||||
TreeNode TreeNode2 = new TreeNode(0);
|
||||
TreeNode TreeNode3 = new TreeNode(4);
|
||||
TreeNode TreeNode4 = new TreeNode(2);
|
||||
TreeNode TreeNode5 = new TreeNode(1);
|
||||
// TreeNode TreeNode6 = new TreeNode(7);
|
||||
|
||||
root.setLeft(TreeNode2);
|
||||
root.setRight(TreeNode3);
|
||||
TreeNode2.setRight(TreeNode4);
|
||||
TreeNode4.setLeft(TreeNode5);
|
||||
// TreeNode3.setRight(TreeNode6);
|
||||
|
||||
TreeNode node = trimBST2(root, 1, 3);
|
||||
|
||||
List<Integer> integers = inorderTraversal1(node);
|
||||
|
||||
System.out.println(integers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初步思路:使用deleteNode一个一个删除
|
||||
*
|
||||
* @param root
|
||||
* @param low
|
||||
* @param high
|
||||
* @return
|
||||
*/
|
||||
public TreeNode trimBST(TreeNode root, int low, int high) {
|
||||
for (int i = low; i < high; i++) {
|
||||
DeleteNodeII deleteNodeII = new DeleteNodeII();
|
||||
root = deleteNodeII.deleteNode(root, i);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 进阶思路:代码随想录递归法
|
||||
* 利用二叉搜索树的特性实现快速删除:找到low,将low.right直接代替low;找到high,将high.left直接代替high
|
||||
* 其他时候比他小就返回修完右边的值,比他大就返回修完左边的值
|
||||
* 速度击败100% 内存击败18.83%
|
||||
* @param root
|
||||
* @param low
|
||||
* @param high
|
||||
* @return
|
||||
*/
|
||||
public TreeNode trimBST2(TreeNode root, int low, int high) {
|
||||
if (root == null) return null;
|
||||
if (root.val < low) return trimBST2(root.right, low, high);
|
||||
if (root.val > high) return trimBST2(root.left, low, high);
|
||||
root.left = trimBST2(root.left, low, high);
|
||||
root.right = trimBST2(root.right, low, high);
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 进阶思路:代码随想录迭代法
|
||||
* 利用二叉搜索树的特性实现快速删除:先找到第一个在区间内的数,以此为根基,分别处理其左节点和右节点,左节点往右移;右节点往左移
|
||||
* 其他时候比他小就返回修完右边的值,比他大就返回修完左边的值
|
||||
* 速度击败100% 内存击败38.55%
|
||||
* @param root
|
||||
* @param low
|
||||
* @param high
|
||||
* @return
|
||||
*/
|
||||
public TreeNode trimBST3(TreeNode root, int low, int high) {
|
||||
if(root==null)return null;
|
||||
|
||||
//处理头结点,让root移动到一个在区间内的数
|
||||
while (root!=null&&(root.val<low||root.val>high)){
|
||||
if(root.val<low)root=root.right;
|
||||
else root= root.left;
|
||||
}
|
||||
|
||||
//找了第一个不是的数
|
||||
|
||||
//处理其左节点
|
||||
TreeNode cur=root;
|
||||
while (cur!=null){
|
||||
while (cur.left!=null&&cur.left.val<low){
|
||||
cur.left=cur.left.right;
|
||||
}
|
||||
//处理完毕,安心将cur左移,继续判断其左节点会不会超过
|
||||
cur=cur.left;
|
||||
//这里不需要判断右节点,因为root在区间内,那么左子树最大也就是root,所以不会超过其右界
|
||||
}
|
||||
|
||||
//在处理其右节点
|
||||
cur=root;
|
||||
while (cur!=null){
|
||||
while (cur.right!=null&&cur.right.val>high){
|
||||
cur.right=cur.right.left;
|
||||
}
|
||||
//处理完毕,安心将cur右移,继续判断其左节点会不会超过
|
||||
cur=cur.right;
|
||||
//这里不需要判断左节点,因为root在区间内,那么右子树最小也就是root,所以不会超过其左界
|
||||
}
|
||||
|
||||
//全部处理完毕,安心返回root
|
||||
return root;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue