leecode更新

This commit is contained in:
markilue 2023-01-09 13:52:17 +08:00
parent cf77fa5d9b
commit 8e4aae2076
8 changed files with 552 additions and 2 deletions

View File

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

View File

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

View File

@ -17,7 +17,7 @@ import java.util.List;
* 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 * 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1
* @Version: 1.0 * @Version: 1.0
*/ */
public class IsBalance { public class T08_IsBalance {
@Test @Test

View File

@ -17,7 +17,7 @@ import java.util.Queue;
* 叶子节点 是指没有子节点的节点 * 叶子节点 是指没有子节点的节点
* @Version: 1.0 * @Version: 1.0
*/ */
public class BinaryTreePaths { public class T09_BinaryTreePaths {
@Test @Test
public void test() { public void test() {

View File

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

View File

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

View File

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

View File

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