leecode更新

This commit is contained in:
markilue 2022-09-26 15:02:18 +08:00
parent 0b8049f176
commit 2bb7fa65b8
3 changed files with 555 additions and 0 deletions

View File

@ -0,0 +1,221 @@
package com.markilue.leecode.tree;
import org.junit.Test;
import java.util.Stack;
/**
* @BelongsProject: Leecode
* @BelongsPackage: com.markilue.leecode.tree
* @Author: dingjiawen
* @CreateTime: 2022-09-26 11:06
* @Description: TODO 力扣98题 验证二叉搜索树
* 给你一个二叉树的根节点 root 判断其是否是一个有效的二叉搜索树
* 有效 二叉搜索树定义如下
* 1.节点的左子树只包含 小于 当前节点的数
* 2.节点的右子树只包含 大于 当前节点的数
* 3.所有左子树和右子树自身必须也是二叉搜索树
* @Version: 1.0
*/
public class IsValidBST {
@Test
public void test() {
TreeNode root = new TreeNode(2);
TreeNode TreeNode2 = new TreeNode(1);
TreeNode TreeNode3 = new TreeNode(3);
// TreeNode TreeNode4 = new TreeNode(5);
TreeNode TreeNode5 = new TreeNode(5);
TreeNode TreeNode6 = new TreeNode(1);
TreeNode TreeNode7 = new TreeNode(4);
TreeNode TreeNode8 = new TreeNode(3);
TreeNode TreeNode9 = new TreeNode(6);
root.setRight(TreeNode3);
root.setLeft(TreeNode2);
// TreeNode2.setLeft(TreeNode4);
TreeNode5.setLeft(TreeNode6);
TreeNode5.setRight(TreeNode7);
TreeNode7.setLeft(TreeNode8);
TreeNode7.setRight(TreeNode9);
System.out.println(isValidBST1(root));
System.out.println(isValidBST1(TreeNode5));
}
@Test
public void test1() {
TreeNode root = new TreeNode(0);
// TreeNode TreeNode2 = new TreeNode(-1);
TreeNode TreeNode3 = new TreeNode(1);
// TreeNode TreeNode4 = new TreeNode(5);
root.setRight(TreeNode3);
// root.setLeft(TreeNode3);
// TreeNode2.setLeft(TreeNode4);
System.out.println(isValidBST1(root));
}
@Test
public void test2() {
TreeNode root = new TreeNode(5);
TreeNode TreeNode2 = new TreeNode(4);
TreeNode TreeNode3 = new TreeNode(6);
TreeNode TreeNode4 = new TreeNode(3);
TreeNode TreeNode5 = new TreeNode(7);
root.setRight(TreeNode3);
root.setLeft(TreeNode2);
TreeNode3.setLeft(TreeNode4);
TreeNode3.setRight(TreeNode5);
System.out.println(isValidBST1(root));
}
@Test
public void test3() {
TreeNode root = new TreeNode(-2147483648);
TreeNode TreeNode2 = new TreeNode(4);
TreeNode TreeNode3 = new TreeNode(2147483647);
TreeNode TreeNode4 = new TreeNode(3);
TreeNode TreeNode5 = new TreeNode(7);
root.setRight(TreeNode3);
// root.setLeft(TreeNode2);
// TreeNode3.setLeft(TreeNode4);
// TreeNode3.setRight(TreeNode5);
System.out.println(isValidBST(root));
}
@Test
public void test4() {
TreeNode root = new TreeNode(3);
TreeNode TreeNode2 = new TreeNode(1);
TreeNode TreeNode3 = new TreeNode(5);
TreeNode TreeNode4 = new TreeNode(0);
TreeNode TreeNode5 = new TreeNode(2);
TreeNode TreeNode6 = new TreeNode(4);
TreeNode TreeNode7 = new TreeNode(6);
root.setRight(TreeNode3);
root.setLeft(TreeNode2);
TreeNode2.setLeft(TreeNode4);
TreeNode2.setRight(TreeNode5);
TreeNode3.setLeft(TreeNode6);
TreeNode3.setRight(TreeNode7);
System.out.println(isValidBST1(root));
}
/**
* 递归法
* 速度超过100%内存超过67.95%
*
* @param root
* @return
*/
public boolean isValidBST(TreeNode root) {
return isValid(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
//limit即一个数的节点一定大于他左节点的右节点小于他右节点的左节点
public boolean isValid(TreeNode root, Long leftLimit, Long rightLimit) {
//第一个条件是为了第一次root等于null的情况理论上不会
if (root.left == null && root.right == null) return true;
boolean flag1 = false;
if (root.left == null) {
flag1 = true;
} else {
if (root.val > root.left.val && root.left.val > leftLimit) {
flag1 = isValid(root.left, leftLimit, Long.valueOf(root.val));
}
}
//快速返回
if (!flag1) {
return false;
}
boolean flag2 = false;
if (root.right == null) {
flag2 = true;
} else {
if (root.val < root.right.val && root.right.val < rightLimit) {
flag2 = isValid(root.right, Long.valueOf(root.val), rightLimit);
}
}
return flag2;
}
/**
* 代码随想录递归法
* 速度超过100%内存超过67.95%
*
* @param root
* @return
*/
TreeNode pre = null;//记录前一个节点
public boolean isValidBST2(TreeNode root) {
if (root == null) return true;
boolean left = isValidBST2(root.left);
if (pre != null && pre.val >= root.val) {
return false;
}
pre = root; //记录前一个节点
boolean right = isValidBST2(root.right);
return left && right;
}
/**
* 迭代法由于左边节点和右边节点的界限不相同,因此不能使用层序遍历这里使用中序遍历
* 速度超过19.02%内存超过11.02%
*
* @param root
* @return
*/
public boolean isValidBST1(TreeNode root) {
if (root == null) {
return false;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode pre = null;//记录前一个节点
TreeNode cur = root;
//
while (!stack.isEmpty() || cur != null) {
if (cur != null) {
stack.push(cur);
cur=cur.left;
} else {
cur = stack.pop();
if (pre != null && cur.val <= pre.val) return false; //这里是1)将左子节点小于本节点 2)本节点的右子节点的所有节点都大于本节点 这两个逻辑统一:通过记录前一个指针来完成,这个操作似乎只能通过中序遍历来完成
pre = cur;//保存访问的前一个节点
cur = cur.right;
}
}
return true;
}
}

View File

@ -0,0 +1,237 @@
package com.markilue.leecode.tree;
import org.junit.Test;
import java.util.*;
/**
* @BelongsProject: Leecode
* @BelongsPackage: com.markilue.leecode.tree
* @Author: dingjiawen
* @CreateTime: 2022-09-26 09:14
* @Description: TODO 力扣617题 合并二叉树
* 1给你两棵二叉树 root1 root2
* 2想象一下当你将其中一棵覆盖到另一棵之上时两棵树上的一些节点将会重叠而另一些不会
* 你需要将这两棵树合并成一棵新二叉树
* 合并的规则是如果两个节点重叠那么将这两个节点的值相加作为合并后节点的新值
* 否则不为 null 的节点将直接作为新二叉树的节点
* 3返回合并后的二叉树
* @Version: 1.0
*/
public class MergeTrees {
@Test
public void test() {
TreeNode root = new TreeNode(1);
TreeNode TreeNode2 = new TreeNode(3);
TreeNode TreeNode3 = new TreeNode(2);
TreeNode TreeNode4 = new TreeNode(5);
TreeNode TreeNode5 = new TreeNode(2);
TreeNode TreeNode6 = new TreeNode(1);
TreeNode TreeNode7 = new TreeNode(3);
TreeNode TreeNode8 = new TreeNode(4);
TreeNode TreeNode9 = new TreeNode(7);
root.setRight(TreeNode3);
root.setLeft(TreeNode2);
TreeNode2.setLeft(TreeNode4);
TreeNode5.setLeft(TreeNode6);
TreeNode5.setRight(TreeNode7);
TreeNode6.setRight(TreeNode8);
TreeNode7.setRight(TreeNode9);
System.out.println(preorderTraversal2(mergeTrees2(root, TreeNode5))); //3 4 5 4 5 7
}
/**
* 自己递归法
* 速度击败100%内存击败96.05%
* 本质上是深度优先算法
* @param root1
* @param root2
* @return
*/
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null) {
return root2;
} else {
if (root2 != null) {
root1.val = root1.val + root2.val;
root1.left = mergeTrees(root1.left, root2.left);
root1.right = mergeTrees(root1.right, root2.right);
}
return root1;
}
}
/**
* 自己迭代法前序层序应该都可以
* 速度击败11.89%内存击败27.67%
*
* @param root1
* @param root2
* @return
*/
public TreeNode mergeTrees1(TreeNode root1, TreeNode root2) {
if (root1 == null) {
return root2;
}
if (root2 == null) {
return root1;
}
//存放root1节点
Stack<TreeNode> treeNodes1 = new Stack<>();
//存放root2节点
Stack<TreeNode> treeNodes2 = new Stack<>();
treeNodes1.push(root1);
treeNodes2.push(root2);
while (!treeNodes1.empty() || !treeNodes2.empty()) {
TreeNode node1 = treeNodes1.pop();
TreeNode node2 = treeNodes2.pop();
if (node2 == null) {
continue;
}
node1.val += node2.val;
if (node1.left != null) {
treeNodes1.push(node1.left);
treeNodes2.push(node2.left);
} else {
node1.left = node2.left;
}
if (node1.right != null) {
treeNodes1.push(node1.right);
treeNodes2.push(node2.right);
} else {
node1.right = node2.right;
}
}
return root1;
}
/**
* 自己迭代法改进版使用一个stack
* 速度击败11.89%内存击败81.44%
* 本质上是广度优先算法
* @param root1
* @param root2
* @return
*/
public TreeNode mergeTrees2(TreeNode root1, TreeNode root2) {
if (root1 == null) {
return root2;
}
//只要root1不等于null即可root2等于0的逻辑在后面也可以判断了
//存放root1节点
Queue<TreeNode> deque = new LinkedList<TreeNode>();
deque.offer(root1);
deque.offer(root2);
while (!deque.isEmpty()) {
TreeNode node1 = deque.poll();
TreeNode node2 = deque.poll();
if (node2 == null) {
continue;
}
node1.val += node2.val;
if (node1.left != null) {
deque.offer(node1.left);
deque.offer(node2.left);
} else {
node1.left = node2.left;
}
if (node1.right != null) {
deque.offer(node1.right);
deque.offer(node2.right);
} else {
node1.right = node2.right;
}
}
return root1;
}
/**
* Morris 遍历将空间复杂度降到O(1)
* Morris 遍历的核心思想是利用树的大量空闲指针实现空间开销的极限缩减其前序遍历规则总结如下
* <p>
* 1.新建临时节点令该节点为 root
* 2.如果当前节点的左子节点为空将当前节点加入答案并遍历当前节点的右子节点
* 3.如果当前节点的左子节点不为空在当前节点的左子树中找到当前节点在中序遍历下的前驱节点
* 如果前驱节点的右子节点为空将前驱节点的右子节点设置为当前节点然后将当前节点加入答案并将前驱节点的右子节点更新为当前节点当前节点更新为当前节点的左子节点
* 如果前驱节点的右子节点为当前节点将它的右子节点重新设为空当前节点更新为当前节点的右子节点
* 4.重复步骤 2 和步骤 3直到遍历结束
* <p>
* TODO 核心理念是如何回到root节点的:
* 1)传统方法使用stack去回到root
* 2)这种方法利用叶子结点闲置的右指针因为回到root的前提是左边的遍历完了那么遍历完了之前的一个节点一定是叶子节点可以提前找到这个叶子结点,将其右指针置为root就可以回到root了
*
* @param root
* @return
*/
public List<Integer> preorderTraversal2(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) {
return res;
}
TreeNode p1 = root, p2 = null;
while (p1 != null) {
p2 = p1.left;
if (p2 != null) {
//通过这个循环找到回到root的最后一个节点,第二个条件是判断是否遍历过这个节点
while (p2.right != null && p2.right != p1) {
p2 = p2.right;
}
//从第一个条件出来的证明这个节点没遍历过且是回到root前的最后一个节点
if (p2.right == null) {
res.add(p1.val);
//让下次得以回到之前遍历的节点
p2.right = p1;
//找到了回来的节点放心的将root左移
p1 = p1.left;
continue;
} else {
//从第二个条件出来的证明这个节点遍历过了,那么就把他的右边置空
p2.right = null;
}
} else {
//左边遍历完了
res.add(p1.val);
}
p1 = p1.right;
}
return res;
}
}

View File

@ -0,0 +1,97 @@
package com.markilue.leecode.tree;
import org.junit.Test;
/**
* @BelongsProject: Leecode
* @BelongsPackage: com.markilue.leecode.tree
* @Author: dingjiawen
* @CreateTime: 2022-09-26 10:31
* @Description: TODO 力扣700题 二叉搜索树中的搜索
* 给定二叉搜索树BST的根节点root和一个整数值val
* 你需要在 BST 中找到节点值等于val的节点 返回以该节点为根的子树 如果节点不存在则返回null
* @Version: 1.0
*/
public class SearchBST {
@Test
public void test() {
TreeNode root = new TreeNode(4);
TreeNode TreeNode2 = new TreeNode(2);
TreeNode TreeNode3 = new TreeNode(7);
TreeNode TreeNode4 = new TreeNode(1);
TreeNode TreeNode5 = new TreeNode(3);
// TreeNode TreeNode5 = new TreeNode(2);
// TreeNode TreeNode6 = new TreeNode(1);
// TreeNode TreeNode7 = new TreeNode(3);
// TreeNode TreeNode8 = new TreeNode(4);
// TreeNode TreeNode9 = new TreeNode(7);
root.setRight(TreeNode3);
root.setLeft(TreeNode2);
TreeNode2.setLeft(TreeNode4);
TreeNode2.setRight(TreeNode5);
//
// TreeNode5.setLeft(TreeNode6);
// TreeNode5.setRight(TreeNode7);
// TreeNode6.setRight(TreeNode8);
// TreeNode7.setRight(TreeNode9);
System.out.println(searchBST(root, 2));
}
/**
* 自己递归法:
* 速度超过100%内存超过94.85%
*
* @param root
* @param val
* @return
*/
public TreeNode searchBST(TreeNode root, int val) {
if (root == null) {
return null;
}
if (root.val > val) {
return searchBST(root.left, val);
} else if (root.val < val) {
return searchBST(root.right, val);
} else {
return root;
}
}
/**
* 自己迭代法:
* 速度超过100%内存超过25.48%
*
* @param root
* @param val
* @return
*/
public TreeNode searchBST1(TreeNode root, int val) {
if (root == null) {
return null;
}
TreeNode node = root;
while (node != null) {
if (node.val > val) {
node = node.left;
} else if (node.val < val) {
node = node.right;
} else {
return node;
}
}
return node;
}
}