leecode更新

This commit is contained in:
markilue 2022-10-08 14:28:53 +08:00
parent 2266507c27
commit 1028801e76
2 changed files with 384 additions and 0 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}