leecode更新
This commit is contained in:
parent
cf77fa5d9b
commit
8e4aae2076
|
|
@ -0,0 +1,73 @@
|
|||
package com.markilue.java_learning.thread;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.junit.Test;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
*@BelongsProject: java_learning
|
||||
*@BelongsPackage: com.markilue.java_learning.thread
|
||||
*@Author: dingjiawen
|
||||
*@CreateTime: 2023-01-08 17:12
|
||||
*@Description:
|
||||
* TODO 测试内存屏障:
|
||||
* 使用unsafe类中的loadFence增加读屏障,保证内存中的数据一致性
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class MemoryBarrier {
|
||||
|
||||
@Test
|
||||
public void test() throws NoSuchFieldException, IllegalAccessException {
|
||||
String s="dingjiawen";
|
||||
System.out.println("first s:"+s);
|
||||
Field value = s.getClass().getDeclaredField("value");
|
||||
value.setAccessible(true);
|
||||
char[] o = (char[])value.get(s);
|
||||
o[1]='b';
|
||||
// value.set(s,"dingjin");
|
||||
System.out.println("last s:"+s);
|
||||
}
|
||||
|
||||
public static void main(String[] args){
|
||||
Unsafe unsafe=null;
|
||||
try {
|
||||
Field field = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
field.setAccessible(true);
|
||||
unsafe = (Unsafe) field.get(null);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
ChangeThread changeThread = new ChangeThread();
|
||||
new Thread(changeThread).start();
|
||||
while (true) {
|
||||
|
||||
boolean flag = changeThread.isFlag();
|
||||
// System.out.println(flag);//奇怪的是,只要加上这句,好像就可以检测到flag的变化
|
||||
// unsafe.loadFence(); //加入读内存屏障
|
||||
if (flag){
|
||||
System.out.println("detected flag changed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.out.println("main thread end");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Getter
|
||||
class ChangeThread implements Runnable{
|
||||
/**volatile**/ boolean flag=false;
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("subThread change flag to:" + flag);
|
||||
flag = true;
|
||||
System.out.println("subThread change flag to:" + flag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
package com.markilue.leecode.tree;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.tree
|
||||
*@Author: dingjiawen
|
||||
*@CreateTime: 2023-01-09 10:56
|
||||
*@Description:
|
||||
* TODO 力扣222题 完全二叉树的节点个数:
|
||||
* 给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
|
||||
* 完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,
|
||||
* 其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T07_CountNodes {
|
||||
|
||||
/**
|
||||
* 思路:递归法,尝试DFS
|
||||
* 速度击败100%,内存击败85.46%
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public int countNodes(TreeNode root) {
|
||||
count(root);
|
||||
return count;
|
||||
}
|
||||
int count=0;
|
||||
public void count(TreeNode node) {
|
||||
if(node==null){
|
||||
return;
|
||||
}
|
||||
count+=1;
|
||||
count(node.left);
|
||||
count(node.right);
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代法:尝试BFS
|
||||
* 速度击败19.63%,内存击败6.91%
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public int countNodes1(TreeNode root) {
|
||||
int count=0;
|
||||
if(root==null){
|
||||
return count;
|
||||
}
|
||||
Queue<TreeNode> queue = new LinkedList<>();
|
||||
queue.offer(root);
|
||||
|
||||
while (!queue.isEmpty()){
|
||||
int size = queue.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
TreeNode node = queue.poll();
|
||||
count++;
|
||||
if(node.left!=null)queue.offer(node.left);
|
||||
if(node.right!=null)queue.offer(node.right);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码随想录针对普通二叉树的解法
|
||||
*
|
||||
*
|
||||
* 速度击败100%,内存击败31.23%
|
||||
*/
|
||||
public int countNodes3(TreeNode root) {
|
||||
if (root == null) return 0;
|
||||
return countNodes3(root.left) + countNodes3(root.right) + 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 代码随想录针对完全二叉树的解法
|
||||
*
|
||||
* 满二叉树的结点数为:2^depth - 1
|
||||
* 速度击败100%,内存击败89.89%
|
||||
*/
|
||||
public int countNodes2(TreeNode root) {
|
||||
if (root == null) return 0;
|
||||
TreeNode left = root.left;
|
||||
TreeNode right = root.right;
|
||||
int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
|
||||
while (left != null) { // 求左子树深度
|
||||
left = left.left;
|
||||
leftDepth++;
|
||||
}
|
||||
while (right != null) { // 求右子树深度
|
||||
right = right.right;
|
||||
rightDepth++;
|
||||
}
|
||||
if (leftDepth == rightDepth) {//左右深度相等,那么就是满二叉树
|
||||
return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
|
||||
}
|
||||
return countNodes2(root.left) + countNodes2(root.right) + 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ import java.util.List;
|
|||
* 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class IsBalance {
|
||||
public class T08_IsBalance {
|
||||
|
||||
|
||||
@Test
|
||||
|
|
@ -17,7 +17,7 @@ import java.util.Queue;
|
|||
* 叶子节点 是指没有子节点的节点。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class BinaryTreePaths {
|
||||
public class T09_BinaryTreePaths {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package com.markilue.leecode.tree.second;
|
||||
|
||||
import com.markilue.leecode.tree.TreeNode;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.tree.second
|
||||
*@Author: dingjiawen
|
||||
*@CreateTime: 2023-01-09 11:15
|
||||
*@Description:
|
||||
* TODO 二刷力扣110题 平衡二叉树:
|
||||
* 给定一个二叉树,判断它是否是高度平衡的二叉树。
|
||||
* 本题中,一棵高度平衡二叉树定义为:
|
||||
* 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T08_IsBalance {
|
||||
|
||||
/**
|
||||
* 思路:递归法:如果两边差大于1了直接返回-1;当-1了就快速返回
|
||||
* 速度击败100%,内存击败57.39%
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public boolean isBalanced(TreeNode root) {
|
||||
if(root==null){
|
||||
return true;
|
||||
}
|
||||
int leftHeight=nodeHeight(root.left);
|
||||
if(leftHeight==-1){
|
||||
return false;
|
||||
}
|
||||
int rightHeight=nodeHeight(root.right);
|
||||
if(rightHeight==-1||Math.abs(leftHeight-rightHeight)>1){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码随想录递归
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public boolean isBalanced1(TreeNode root) {
|
||||
return nodeHeight(root) == -1 ? false : true;
|
||||
}
|
||||
|
||||
public int nodeHeight(TreeNode node) {
|
||||
if(node==null){
|
||||
return 0;
|
||||
}
|
||||
int leftHeight=nodeHeight(node.left);
|
||||
if(leftHeight==-1){
|
||||
return -1;
|
||||
}
|
||||
int rightHeight=nodeHeight(node.right);
|
||||
if(rightHeight==-1||Math.abs(leftHeight-rightHeight)>1){
|
||||
return -1;
|
||||
}
|
||||
return Math.max(leftHeight,rightHeight)+1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 思路:迭代法,后序遍历是一个比较好的方式
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public boolean isBalanced2(TreeNode root) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package com.markilue.leecode.tree.second;
|
||||
|
||||
import com.markilue.leecode.tree.TreeNode;
|
||||
import com.markilue.leecode.tree.TreeUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.tree.second
|
||||
*@Author: dingjiawen
|
||||
*@CreateTime: 2023-01-09 11:45
|
||||
*@Description:
|
||||
* TODO 二刷力扣257题 二叉树的所有路径:
|
||||
* 给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
|
||||
* 叶子节点 是指没有子节点的节点。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T09_0_BinaryTreePaths {
|
||||
@Test
|
||||
public void test(){
|
||||
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(1,-2,3,null,5));
|
||||
TreeNode root = TreeUtils.structureTree(list, 0);
|
||||
System.out.println(binaryTreePaths(root));
|
||||
}
|
||||
|
||||
/**
|
||||
* 思路:经典前序遍历递归回溯问题
|
||||
* 速度击败100%,内存击败71.19%。回溯的删除路径是这题比较麻烦的点,因为他添加的数字位数无法确定
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public List<String> binaryTreePaths(TreeNode root) {
|
||||
String curPath="";
|
||||
backtracking1(root,curPath);
|
||||
return totalPath;
|
||||
}
|
||||
//curPath记录当前路径
|
||||
List<String> totalPath=new ArrayList<>();//记录全部路径
|
||||
public void backtracking(TreeNode node,StringBuilder curPath){
|
||||
curPath.append(node.val);
|
||||
|
||||
if(node.left==null&&node.right==null){
|
||||
totalPath.add(new String(curPath));
|
||||
return;
|
||||
}
|
||||
|
||||
if(node.left!=null){
|
||||
backtracking(node.left,curPath.append("->"));//否则有下一个节点,所以先拼上->
|
||||
curPath.delete(curPath.length()-2,curPath.length());
|
||||
}
|
||||
if(node.right!=null){
|
||||
backtracking(node.right,curPath.append("->"));
|
||||
curPath.delete(curPath.length()-2,curPath.length());
|
||||
}
|
||||
curPath.delete(curPath.lastIndexOf(node.val+""),curPath.length());
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void backtracking1(TreeNode node,String curPath){
|
||||
StringBuilder builder = new StringBuilder(curPath);
|
||||
builder.append(node.val);
|
||||
if(node.left==null&&node.right==null){
|
||||
totalPath.add(new String(builder));
|
||||
return;
|
||||
}
|
||||
|
||||
int length2 = builder.length();
|
||||
if(node.left!=null){
|
||||
backtracking1(node.left,new String(builder.append("->")));//否则有下一个节点,所以先拼上->
|
||||
builder.delete(length2,builder.length());
|
||||
}
|
||||
int length1 = builder.length();
|
||||
if(node.right!=null){
|
||||
backtracking1(node.right,new String(builder.append("->")));
|
||||
builder.delete(length1,builder.length());
|
||||
}
|
||||
|
||||
// builder.delete(length,length1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 官方比较漂亮的写法
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public List<String> binaryTreePaths1(TreeNode root) {
|
||||
List<String> result = new ArrayList<>();
|
||||
constructPaths(root,"",result);
|
||||
return result;
|
||||
}
|
||||
//这里使用StringBuilder,因为他快是因为他适用于同一个string不可变字符串的时候,这里每一个只添加一次
|
||||
//这里处理node的左右节点,而不是处理他本身,因为涉及到要不要新new上一个List
|
||||
public void constructPaths(TreeNode node,String path, List<String> result) {
|
||||
|
||||
if(node!=null){
|
||||
StringBuilder pathDS = new StringBuilder(path);
|
||||
pathDS.append(node.val);
|
||||
//遍历到了叶子结点,可以把结果加入
|
||||
if(node.left==null&&node.right==null){
|
||||
result.add(pathDS.toString());
|
||||
}else{
|
||||
//不是叶子节点,需要继续遍历
|
||||
pathDS.append("->");
|
||||
constructPaths(node.left,pathDS.toString(),result);
|
||||
constructPaths(node.right,pathDS.toString(),result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package com.markilue.leecode.tree.second;
|
||||
|
||||
import com.markilue.leecode.tree.TreeNode;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.tree.second
|
||||
*@Author: dingjiawen
|
||||
*@CreateTime: 2023-01-09 12:46
|
||||
*@Description:
|
||||
* TODO 力扣100题 相同的树:
|
||||
* 给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
|
||||
* 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T09_1_IsSameTree {
|
||||
|
||||
/**
|
||||
* 思路:即完全相同,值相同子树不相同也可以,实际上可以依次遍历个节点。递归法DFS前序遍历
|
||||
* 速度击败100%,内存击败72.54%
|
||||
* @param p
|
||||
* @param q
|
||||
* @return
|
||||
*/
|
||||
public boolean isSameTree(TreeNode p, TreeNode q) {
|
||||
if(p==null&&q==null){
|
||||
return true;
|
||||
}
|
||||
if(p==null||q==null)return false;//其中一个为null
|
||||
return p.val==q.val&&isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);//都不为null
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 思路:即完全相同,值相同子树不相同也可以,实际上可以依次遍历个节点。迭代法BFS
|
||||
* 速度击败100%,内存击败20.92%
|
||||
* @param p
|
||||
* @param q
|
||||
* @return
|
||||
*/
|
||||
public boolean isSameTree1(TreeNode p, TreeNode q) {
|
||||
if(p==null&&q==null){
|
||||
return true;
|
||||
}
|
||||
if(p==null||q==null)return false;//其中一个为null
|
||||
Stack<TreeNode> stack = new Stack<>();
|
||||
stack.push(p);
|
||||
stack.push(q);//一直同进同出即可
|
||||
while (!stack.isEmpty()){
|
||||
int size = stack.size();
|
||||
for (int i = 0; i < size; i+=2) {
|
||||
TreeNode node1 = stack.pop();
|
||||
TreeNode node2 = stack.pop();
|
||||
if(node1==null&&node2==null){
|
||||
continue;
|
||||
}
|
||||
if(node1==null||node2==null){
|
||||
return false;//其中一个为null
|
||||
}else {
|
||||
//全不为null
|
||||
if(node1.val!=node2.val){
|
||||
return false;
|
||||
}
|
||||
stack.push(node1.left);
|
||||
stack.push(node2.left);
|
||||
stack.push(node1.right);
|
||||
stack.push(node2.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;//都不为null
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
package com.markilue.leecode.tree.second;
|
||||
|
||||
import com.markilue.leecode.tree.TreeNode;
|
||||
import com.markilue.leecode.tree.TreeUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.tree.second
|
||||
*@Author: dingjiawen
|
||||
*@CreateTime: 2023-01-09 13:00
|
||||
*@Description:
|
||||
* TODO 力扣572题 另一颗子树:
|
||||
* 给你两棵二叉树 root 和 subRoot 。
|
||||
* 检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
|
||||
* 二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
|
||||
*
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T09_2_IsSubtree {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3,4,5,1,2));
|
||||
ArrayList<Integer> list1 = new ArrayList<>(Arrays.asList(4,1,2));
|
||||
TreeNode root = TreeUtils.structureTree(list, 0);
|
||||
TreeNode subRoot = TreeUtils.structureTree(list1, 0);
|
||||
System.out.println(isSubtree(root,subRoot));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 思路:T09_1的浅进阶,找到相同的root后,开始比较子树
|
||||
* 速度击败92.32%,内存击败70.43%
|
||||
* @param root
|
||||
* @param subRoot
|
||||
* @return
|
||||
*/
|
||||
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
|
||||
if(root==null&&subRoot==null){
|
||||
return true;
|
||||
}
|
||||
if(root==null||subRoot==null){
|
||||
return false;//其中一个为null
|
||||
}
|
||||
boolean flag=false;
|
||||
boolean flag1=false;
|
||||
if(root.val==subRoot.val){
|
||||
//现在相同子树对象
|
||||
flag=isSameTree(root.left,subRoot.left)&&isSameTree(root.right,subRoot.right);
|
||||
}
|
||||
if(flag==false){//在开始比较两个子树的过程中就不能进这个了
|
||||
flag=isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot);//只要有子树一样即可
|
||||
}
|
||||
return flag;
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
* 思路:即完全相同,值相同子树不相同也可以,实际上可以依次遍历个节点。递归法DFS前序遍历
|
||||
* 速度击败100%,内存击败72.54%
|
||||
* @param p
|
||||
* @param q
|
||||
* @return
|
||||
*/
|
||||
public boolean isSameTree(TreeNode p, TreeNode q) {
|
||||
if(p==null&&q==null){
|
||||
return true;
|
||||
}
|
||||
if(p==null||q==null)return false;//其中一个为null
|
||||
return p.val==q.val&&isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);//都不为null
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方最快
|
||||
* 速度击败100%,内存击败5.4%
|
||||
* @param root
|
||||
* @param subRoot
|
||||
* @return
|
||||
*/
|
||||
public boolean isSubtree1(TreeNode root, TreeNode subRoot) {
|
||||
if(root==null&&subRoot!=null) return false;
|
||||
if(root!=null&&subRoot==null) return false;
|
||||
if(root==null&&subRoot==null) return true;
|
||||
if(root.val==subRoot.val){
|
||||
boolean res=isSametree1(root,subRoot);
|
||||
if(res==true) return res;
|
||||
}
|
||||
boolean leftIsSubtree=isSubtree(root.left,subRoot);
|
||||
boolean rightIsSubtree=isSubtree(root.right,subRoot);
|
||||
return leftIsSubtree||rightIsSubtree;
|
||||
|
||||
}
|
||||
public boolean isSametree1(TreeNode root, TreeNode subRoot) {
|
||||
if(root==null&&subRoot!=null) return false;
|
||||
if(root!=null&&subRoot==null) return false;
|
||||
if(root==null&&subRoot==null) return true;
|
||||
if(root.val!=subRoot.val) return false;
|
||||
boolean leftIsSametree=isSametree1(root.left,subRoot.left);
|
||||
boolean rightIsSametree=isSubtree1(root.right,subRoot.right);
|
||||
return leftIsSametree&&rightIsSametree;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue