leecode更新
This commit is contained in:
parent
f07804340e
commit
2266507c27
|
|
@ -0,0 +1,187 @@
|
||||||
|
package com.markilue.leecode.tree;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @BelongsProject: Leecode
|
||||||
|
* @BelongsPackage: com.markilue.leecode.tree
|
||||||
|
* @Author: dingjiawen
|
||||||
|
* @CreateTime: 2022-10-07 12:08
|
||||||
|
* @Description:
|
||||||
|
* TODO leecode 701题 二叉搜索树中的插入操作:
|
||||||
|
* 给定二叉搜索树(BST)的根节点root和要插入树中的值value,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
|
||||||
|
* 注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
|
||||||
|
*
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class InsertIntoBST {
|
||||||
|
|
||||||
|
@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 TreeNode6 = new TreeNode(0);
|
||||||
|
// TreeNode TreeNode7 = new TreeNode(8);
|
||||||
|
// TreeNode TreeNode8 = new TreeNode(7);
|
||||||
|
// TreeNode TreeNode9 = new TreeNode(4);
|
||||||
|
|
||||||
|
root.setRight(TreeNode3);
|
||||||
|
root.setLeft(TreeNode2);
|
||||||
|
TreeNode2.setLeft(TreeNode4);
|
||||||
|
TreeNode2.setRight(TreeNode5);
|
||||||
|
// TreeNode3.setRight(TreeNode7);
|
||||||
|
// TreeNode3.setLeft(TreeNode6);
|
||||||
|
// TreeNode5.setLeft(TreeNode8);
|
||||||
|
// TreeNode5.setRight(TreeNode9);
|
||||||
|
|
||||||
|
System.out.println(inorderTraversal4(insertIntoBST2(root,5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归法:找到叶子结点即可将val加入
|
||||||
|
* 速度击败100%,内存击败5.13%
|
||||||
|
* @param root
|
||||||
|
* @param val
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TreeNode insertIntoBST(TreeNode root, int val) {
|
||||||
|
if(root==null) return new TreeNode(val);
|
||||||
|
if(root.val>val){
|
||||||
|
root.left=insertIntoBST(root.left,val);
|
||||||
|
}else {
|
||||||
|
root.right=insertIntoBST(root.right,val);
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代码随想录无返回值递归法:仍然是找到叶子结点即可加入,利用一个parent节点记录之前的节点
|
||||||
|
* @param root
|
||||||
|
* @param val
|
||||||
|
*/
|
||||||
|
TreeNode parent=null;
|
||||||
|
public void insert(TreeNode root, int val) {
|
||||||
|
if(root==null){
|
||||||
|
TreeNode node = new TreeNode(val);
|
||||||
|
if(parent.val>val){
|
||||||
|
parent.left=node;
|
||||||
|
}else {
|
||||||
|
parent.right=node;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
parent=root;
|
||||||
|
if(root.val>val){
|
||||||
|
insertIntoBST(root.left,val);
|
||||||
|
}else {
|
||||||
|
insertIntoBST(root.right,val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TreeNode insertIntoBST1(TreeNode root, int val) {
|
||||||
|
if(root==null) return new TreeNode(val);
|
||||||
|
insert(root,val);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 迭代法:
|
||||||
|
* 速度击败100% 内存击败12.67%
|
||||||
|
* @param root
|
||||||
|
* @param val
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TreeNode insertIntoBST2(TreeNode root, int val) {
|
||||||
|
if(root==null) return new TreeNode(val);
|
||||||
|
|
||||||
|
TreeNode last=null;
|
||||||
|
|
||||||
|
TreeNode temp=root;
|
||||||
|
|
||||||
|
while (temp!=null){
|
||||||
|
last=temp;
|
||||||
|
if(temp.val>val){
|
||||||
|
temp=temp.left;
|
||||||
|
}else {
|
||||||
|
temp=temp.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(last.val>val){
|
||||||
|
last.left=new TreeNode(val);
|
||||||
|
}else {
|
||||||
|
last.right=new TreeNode(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自己尝试Morris中序遍历
|
||||||
|
* 速度超过100%,内存超过81.82%
|
||||||
|
* @param root
|
||||||
|
*/
|
||||||
|
public static List<Integer> inorderTraversal4(TreeNode root) {
|
||||||
|
|
||||||
|
List<Integer> list1 = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
TreeNode node1 = root;
|
||||||
|
TreeNode node2 = null;
|
||||||
|
|
||||||
|
while (node1 != null) {
|
||||||
|
node2 = node1.left;
|
||||||
|
|
||||||
|
//判断左边还有没有值
|
||||||
|
if(node2!=null){
|
||||||
|
//首先找到遍历node1之前的最后一个节点
|
||||||
|
while (node2.right != null && node2.right != node1) {
|
||||||
|
node2 = node2.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断是从哪个条件出来的
|
||||||
|
if (node2.right == null) {
|
||||||
|
//如果是从第一个条件出来的,那么就是没有遍历过得节点
|
||||||
|
|
||||||
|
//将这个节点的右边定为node1方便以后回来,找到node1
|
||||||
|
node2.right = node1;
|
||||||
|
//node1已经可以回溯,放心将node1左移
|
||||||
|
node1 = node1.left;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
//如果是从第二个条件出来的,那么就是遍历过的节点
|
||||||
|
|
||||||
|
//那么他的左边一定是遍历完了,这时将node的值加入结果
|
||||||
|
list1.add(node1.val);
|
||||||
|
//左边遍历完了,往右移
|
||||||
|
node1 = node1.right;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
//左边没值了
|
||||||
|
list1.add(node1.val);
|
||||||
|
node1=node1.right;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return list1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,208 @@
|
||||||
|
package com.markilue.leecode.tree;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @BelongsProject: Leecode
|
||||||
|
* @BelongsPackage: com.markilue.leecode.tree
|
||||||
|
* @Author: dingjiawen
|
||||||
|
* @CreateTime: 2022-10-07 09:30
|
||||||
|
* @Description: TODO 力扣236题 二叉树的最近公共祖先:
|
||||||
|
* 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
|
||||||
|
* 百度百科中最近公共祖先的定义为:
|
||||||
|
* “对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class LowestCommonAncestor {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
TreeNode root = new TreeNode(3);
|
||||||
|
TreeNode TreeNode2 = new TreeNode(5);
|
||||||
|
TreeNode TreeNode3 = new TreeNode(1);
|
||||||
|
TreeNode TreeNode4 = new TreeNode(6);
|
||||||
|
TreeNode TreeNode5 = new TreeNode(2);
|
||||||
|
TreeNode TreeNode6 = new TreeNode(0);
|
||||||
|
TreeNode TreeNode7 = new TreeNode(8);
|
||||||
|
TreeNode TreeNode8 = new TreeNode(7);
|
||||||
|
TreeNode TreeNode9 = new TreeNode(4);
|
||||||
|
|
||||||
|
root.setRight(TreeNode3);
|
||||||
|
root.setLeft(TreeNode2);
|
||||||
|
TreeNode2.setLeft(TreeNode4);
|
||||||
|
TreeNode2.setRight(TreeNode5);
|
||||||
|
TreeNode3.setRight(TreeNode7);
|
||||||
|
TreeNode3.setLeft(TreeNode6);
|
||||||
|
TreeNode5.setLeft(TreeNode8);
|
||||||
|
TreeNode5.setRight(TreeNode9);
|
||||||
|
|
||||||
|
System.out.println(lowestCommonAncestor1(root, TreeNode2, TreeNode3).val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
TreeNode root = new TreeNode(3);
|
||||||
|
TreeNode TreeNode2 = new TreeNode(5);
|
||||||
|
TreeNode TreeNode3 = new TreeNode(1);
|
||||||
|
TreeNode TreeNode4 = new TreeNode(6);
|
||||||
|
TreeNode TreeNode5 = new TreeNode(2);
|
||||||
|
TreeNode TreeNode6 = new TreeNode(0);
|
||||||
|
TreeNode TreeNode7 = new TreeNode(8);
|
||||||
|
TreeNode TreeNode8 = new TreeNode(7);
|
||||||
|
TreeNode TreeNode9 = new TreeNode(4);
|
||||||
|
|
||||||
|
root.setRight(TreeNode3);
|
||||||
|
root.setLeft(TreeNode2);
|
||||||
|
TreeNode2.setLeft(TreeNode4);
|
||||||
|
TreeNode2.setRight(TreeNode5);
|
||||||
|
TreeNode3.setRight(TreeNode7);
|
||||||
|
TreeNode3.setLeft(TreeNode6);
|
||||||
|
TreeNode5.setLeft(TreeNode8);
|
||||||
|
TreeNode5.setRight(TreeNode9);
|
||||||
|
|
||||||
|
System.out.println(lowestCommonAncestor1(root, TreeNode2, TreeNode9).val);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本人思路:递归法:用一个boolean值记录是否找到了p,q如果找到了就可以返回当前叶子节点
|
||||||
|
* 速度超过5.09%,内存超过38.12%
|
||||||
|
* 慢之处在于即使找到了还需要继续遍历,因为本人这种方式是自顶向下遍历的方式,找到的不一定是最近公共祖先,只能通过不断遍历的方式确定
|
||||||
|
*
|
||||||
|
* @param root
|
||||||
|
* @param p
|
||||||
|
* @param q
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
|
||||||
|
find(root, p, q);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TreeNode result = null;
|
||||||
|
boolean flag = false;
|
||||||
|
|
||||||
|
public boolean find(TreeNode root, TreeNode p, TreeNode q) {
|
||||||
|
if (root == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//记录两个树值是否找到
|
||||||
|
boolean flagp = false;
|
||||||
|
boolean flagq = false;
|
||||||
|
|
||||||
|
|
||||||
|
if (p != null) {
|
||||||
|
if (root.val == p.val) {
|
||||||
|
flagp = true;
|
||||||
|
} else {
|
||||||
|
//这里只找p
|
||||||
|
flagp = find(root.left, p, null) || find(root.right, p, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (q != null) {
|
||||||
|
if (root.val == q.val) {
|
||||||
|
flagq = true;
|
||||||
|
} else {
|
||||||
|
flagq = find(root.left, null, q) || find(root.right, null, q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (flagp && flagq) {
|
||||||
|
result = root;
|
||||||
|
find(root.left, p, q);
|
||||||
|
find(root.right, p, q);
|
||||||
|
// flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return flagp || flagq;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代码随想录思路:递归法:最近节点->如果能自底向上查找就好了,因此可以使用回溯,回溯的过程就是自底向上,二叉树的后续遍历就符合回溯过程,先处理的一定是叶子结点
|
||||||
|
* 速度超过100%,内存超过28.79%
|
||||||
|
* <p>
|
||||||
|
* 递归三部曲:
|
||||||
|
* 1)确定递归函数返回值和参数:TreeNode 找到了就返回这个节点
|
||||||
|
* 2)确定终止条件:找到p或q或者空节点就返回
|
||||||
|
* 3)确定单层递归逻辑:通过递归函数确定该节点是不是公共节点
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param root
|
||||||
|
* @param p
|
||||||
|
* @param q
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
|
||||||
|
//这里之所以可以直接等于就返回,是因为后边还有判断right边有没有,如果right边没有,那么一定是在left边的子树上,这里默认两个子树一定存在。
|
||||||
|
if (root == p || root == q || root == null) return root;
|
||||||
|
|
||||||
|
TreeNode left = lowestCommonAncestor1(root.left, p, q);
|
||||||
|
TreeNode right = lowestCommonAncestor1(root.right, p, q);
|
||||||
|
|
||||||
|
//如果left和right都有值,那么证明当前节点就是最近
|
||||||
|
//反之如果任意没有值就返回另一边
|
||||||
|
if(left!=null&&right!=null){
|
||||||
|
return root;
|
||||||
|
}else if(left==null){
|
||||||
|
return right;
|
||||||
|
}else {
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Map<Integer, TreeNode> parent = new HashMap<Integer, TreeNode>();
|
||||||
|
Set<Integer> visited = new HashSet<Integer>();
|
||||||
|
|
||||||
|
public void dfs(TreeNode root) {
|
||||||
|
if (root.left != null) {
|
||||||
|
parent.put(root.left.val, root);
|
||||||
|
dfs(root.left);
|
||||||
|
}
|
||||||
|
if (root.right != null) {
|
||||||
|
parent.put(root.right.val, root);
|
||||||
|
dfs(root.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方另一种解法:利用map记录父节点,q不断回溯来寻找最近节点
|
||||||
|
* @param root
|
||||||
|
* @param p
|
||||||
|
* @param q
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
|
||||||
|
dfs(root);
|
||||||
|
while (p != null) {
|
||||||
|
visited.add(p.val);
|
||||||
|
p = parent.get(p.val);
|
||||||
|
}
|
||||||
|
while (q != null) {
|
||||||
|
if (visited.contains(q.val)) {
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
q = parent.get(q.val);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
package com.markilue.leecode.tree;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @BelongsProject: Leecode
|
||||||
|
* @BelongsPackage: com.markilue.leecode.tree
|
||||||
|
* @Author: dingjiawen
|
||||||
|
* @CreateTime: 2022-10-07 11:29
|
||||||
|
* @Description: TODO leecode 235题 二叉搜索树的最近公共祖先:
|
||||||
|
* 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
|
||||||
|
* 百度百科中最近公共祖先的定义为:
|
||||||
|
* “对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class LowestCommonAncestorII {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
TreeNode root = new TreeNode(6);
|
||||||
|
TreeNode TreeNode2 = new TreeNode(2);
|
||||||
|
TreeNode TreeNode3 = new TreeNode(8);
|
||||||
|
TreeNode TreeNode4 = new TreeNode(0);
|
||||||
|
TreeNode TreeNode5 = new TreeNode(4);
|
||||||
|
TreeNode TreeNode6 = new TreeNode(7);
|
||||||
|
TreeNode TreeNode7 = new TreeNode(9);
|
||||||
|
TreeNode TreeNode8 = new TreeNode(3);
|
||||||
|
TreeNode TreeNode9 = new TreeNode(5);
|
||||||
|
|
||||||
|
root.setRight(TreeNode3);
|
||||||
|
root.setLeft(TreeNode2);
|
||||||
|
TreeNode2.setLeft(TreeNode4);
|
||||||
|
TreeNode2.setRight(TreeNode5);
|
||||||
|
TreeNode3.setRight(TreeNode7);
|
||||||
|
TreeNode3.setLeft(TreeNode6);
|
||||||
|
TreeNode5.setLeft(TreeNode8);
|
||||||
|
TreeNode5.setRight(TreeNode9);
|
||||||
|
|
||||||
|
System.out.println(lowestCommonAncestor(root, TreeNode2, TreeNode3).val);
|
||||||
|
System.out.println(lowestCommonAncestor(root, TreeNode2, TreeNode5).val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 二叉搜索树的特性:root节点比左边大,右边小
|
||||||
|
* 速度击败36.19%,内存击败82.68%
|
||||||
|
* @param root
|
||||||
|
* @param p
|
||||||
|
* @param q
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
|
||||||
|
|
||||||
|
|
||||||
|
if (root == null ) return root;
|
||||||
|
if(root.val>p.val&&root.val>q.val){
|
||||||
|
return lowestCommonAncestor(root.left, p, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(root.val<p.val&&root.val<q.val){
|
||||||
|
return lowestCommonAncestor(root.right, p, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 迭代法:依然是利用当前节点比左边大比右边节点小这个特性
|
||||||
|
* @param root
|
||||||
|
* @param p
|
||||||
|
* @param q
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
|
||||||
|
TreeNode ancestor = root;
|
||||||
|
while (true) {
|
||||||
|
if (p.val < ancestor.val && q.val < ancestor.val) {
|
||||||
|
ancestor = ancestor.left;
|
||||||
|
} else if (p.val > ancestor.val && q.val > ancestor.val) {
|
||||||
|
ancestor = ancestor.right;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ancestor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue