leecode更新
This commit is contained in:
parent
8e4aae2076
commit
64abd13286
|
|
@ -0,0 +1,133 @@
|
||||||
|
package com.markilue.leecode.tree;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.tree.second
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2023-01-10 10:12
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣404 左子树之和:
|
||||||
|
* 给定二叉树的根节点 root ,返回所有左叶子之和。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T10_SumOfLeftLeaves {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3, 9, 20, null, null, 15, 7));
|
||||||
|
TreeNode root = TreeUtils.structureTree(list, 0);
|
||||||
|
System.out.println(sumOfLeftLeaves(root));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
|
||||||
|
TreeNode root = TreeUtils.structureTree(list, 0);
|
||||||
|
System.out.println(sumOfLeftLeaves(root));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:左叶子节点(叶子节点:左右没有节点,且是左节点) 迭代法中序遍历不处理中节点即可
|
||||||
|
* 速度击败10.5%,内存击败80.37%
|
||||||
|
* @param root
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int sumOfLeftLeaves(TreeNode root) {
|
||||||
|
int sum = 0;
|
||||||
|
if (root == null) {
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
Stack<TreeNode> stack = new Stack<>();
|
||||||
|
TreeNode cur = root;
|
||||||
|
TreeNode jin = root;//不让他加入的节点
|
||||||
|
while (cur != null || !stack.isEmpty()) {
|
||||||
|
if (cur != null) {
|
||||||
|
if (cur != jin && cur.left == null && cur.right == null) {
|
||||||
|
sum += cur.val;
|
||||||
|
}
|
||||||
|
stack.push(cur);
|
||||||
|
cur = cur.left;
|
||||||
|
} else {
|
||||||
|
cur = stack.pop();
|
||||||
|
cur = cur.right;
|
||||||
|
jin = cur;//刚刚进入右节点则不能让他加
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:左叶子节点(叶子节点:左右没有节点,且是左节点) 递归法中序遍历不处理中节点即可
|
||||||
|
* 速度击败100%,内存击败84.12%
|
||||||
|
* @param root
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int sumOfLeftLeaves1(TreeNode root) {
|
||||||
|
if (root == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return travelLeftLeaves1(root, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遍历,看看node是不是pre的左节点来判断
|
||||||
|
* @param node
|
||||||
|
* @param pre
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int travelLeftLeaves1(TreeNode node, TreeNode pre) {
|
||||||
|
if (node == null) {//节点为null不用继续遍历
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (pre != null && pre.left == node && node.left == null && node.right == null) {
|
||||||
|
return node.val;//左叶子节点,加上这个值
|
||||||
|
}
|
||||||
|
return travelLeftLeaves1(node.left, node) + travelLeftLeaves1(node.right, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方BFS:之前都是dfs这里试试BFS法,核心在于不是处理当前节点,而是在父节点判断左节点是不是叶子结点
|
||||||
|
* 速度击败100%,内存击败47.69%
|
||||||
|
* @param root
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int sumOfLeftLeaves3(TreeNode root) {
|
||||||
|
if (root == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Queue<TreeNode> queue = new LinkedList<TreeNode>();
|
||||||
|
queue.offer(root);
|
||||||
|
int ans = 0;
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
TreeNode node = queue.poll();
|
||||||
|
if (node.left != null) {
|
||||||
|
if (isLeafNode(node.left)) {
|
||||||
|
ans += node.left.val;
|
||||||
|
} else {
|
||||||
|
queue.offer(node.left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node.right != null) {
|
||||||
|
if (!isLeafNode(node.right)) {
|
||||||
|
queue.offer(node.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLeafNode(TreeNode node) {
|
||||||
|
return node.left == null && node.right == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
package com.markilue.leecode.tree;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.tree
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2023-01-10 10:53
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣513题 找左下角的值:
|
||||||
|
* 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
|
||||||
|
* 假设二叉树中至少有一个节点。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T11_FindBottomLeftValue {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:不仅要最底层,还要最左;事实上层序遍历就是一个很好地选择
|
||||||
|
* 速度击败13.85%,内存击败45.94% 2ms
|
||||||
|
* @param root
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findBottomLeftValue(TreeNode root) {
|
||||||
|
int value = 0;
|
||||||
|
if (root == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
if (i == 0) {
|
||||||
|
//每层的最左边
|
||||||
|
value = node.val;
|
||||||
|
}
|
||||||
|
if (node.left != null) queue.offer(node.left);
|
||||||
|
if (node.right != null) queue.offer(node.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:不仅要最底层,还要最左;事实上层序遍历就是一个很好地选择,尝试递归DFS
|
||||||
|
* 速度击败100%,内存击败65.25% 0ms
|
||||||
|
* @param root
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findBottomLeftValue1(TreeNode root) {
|
||||||
|
find(root,0);
|
||||||
|
return result.get(result.size()-1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//记录每层最右
|
||||||
|
List<Integer> result=new ArrayList<>();
|
||||||
|
public void find(TreeNode node, int deep) {
|
||||||
|
if (node == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(result.size()==deep){
|
||||||
|
result.add(node.val);
|
||||||
|
}
|
||||||
|
find(node.left,deep+1);
|
||||||
|
find(node.right,deep+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,7 @@ import java.util.Stack;
|
||||||
* 叶子节点 是指没有子节点的节点。
|
* 叶子节点 是指没有子节点的节点。
|
||||||
* @Version: 1.0
|
* @Version: 1.0
|
||||||
*/
|
*/
|
||||||
public class HasPathSum {
|
public class T12_HasPathSum {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
|
|
@ -14,7 +14,7 @@ import java.util.*;
|
||||||
* 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
|
* 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
|
||||||
* @Version: 1.0
|
* @Version: 1.0
|
||||||
*/
|
*/
|
||||||
public class PathSum {
|
public class T13_PathSum {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -13,7 +13,7 @@ import java.util.*;
|
||||||
* 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗二叉树。
|
* 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗二叉树。
|
||||||
* @Version: 1.0
|
* @Version: 1.0
|
||||||
*/
|
*/
|
||||||
public class BuildTree {
|
public class T14_BuildTree {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
package com.markilue.leecode.tree.second;
|
||||||
|
|
||||||
|
import com.markilue.leecode.tree.TreeNode;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.tree.second
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2023-01-10 11:33
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣112题 二刷路径总和:
|
||||||
|
* 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。
|
||||||
|
* 判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。
|
||||||
|
* 如果存在,返回 true ;否则,返回 false 。
|
||||||
|
* 叶子节点 是指没有子节点的节点。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T12_HasPathSum {
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
Integer sum=1000;
|
||||||
|
int i = sum.intValue();
|
||||||
|
System.out.println(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:核心就在于在叶子结点时就判断targetSum;DFS
|
||||||
|
* @param root
|
||||||
|
* @param targetSum
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean hasPathSum(TreeNode root, int targetSum) {
|
||||||
|
if (root == null) {//避免开始就是空的情况
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (root.left == null && root.right == null) {//在叶子结点就处理逻辑
|
||||||
|
return root.val == targetSum;
|
||||||
|
}
|
||||||
|
int nextTarget = targetSum - root.val;
|
||||||
|
return hasPathSum(root.left, nextTarget) || hasPathSum(root.right, nextTarget);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:非递归法DFS
|
||||||
|
* 速度击败6.83%,内存击败58.93%
|
||||||
|
* @param root
|
||||||
|
* @param targetSum
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean hasPathSum1(TreeNode root, int targetSum) {
|
||||||
|
if (root == null) {//避免开始就是空的情况
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Stack<TreeNode> stack = new Stack<>();
|
||||||
|
Stack<Integer> stackSum = new Stack<>();
|
||||||
|
stack.push(root);
|
||||||
|
stackSum.push(0);
|
||||||
|
while (!stack.isEmpty()){
|
||||||
|
TreeNode node = stack.pop();
|
||||||
|
Integer sum = stackSum.pop();
|
||||||
|
sum+=node.val;
|
||||||
|
if(node.left==null&&node.right==null){
|
||||||
|
if(sum.intValue()==targetSum){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(node.left!=null){
|
||||||
|
stack.push(node.left);
|
||||||
|
stackSum.push(sum);
|
||||||
|
}
|
||||||
|
if(node.right!=null){
|
||||||
|
stack.push(node.right);
|
||||||
|
stackSum.push(sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
package com.markilue.leecode.tree.second;
|
||||||
|
|
||||||
|
import com.markilue.leecode.tree.TreeNode;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.tree.second
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2023-01-10 11:52
|
||||||
|
*@Description:
|
||||||
|
* TODO 二刷力扣113题 路径总和II:
|
||||||
|
* 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
|
||||||
|
* 叶子节点 是指没有子节点的节点。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T13_PathSum {
|
||||||
|
|
||||||
|
List<Integer> cur=new ArrayList<>();
|
||||||
|
List<List<Integer>> result=new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归法:
|
||||||
|
* 速度击败99.98%,内存击败88.17%
|
||||||
|
* @param root
|
||||||
|
* @param targetSum
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
|
||||||
|
travel(root,targetSum);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
public void travel(TreeNode node, int targetSum){
|
||||||
|
if(node==null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cur.add(node.val);
|
||||||
|
if(node.left==null&&node.right==null){
|
||||||
|
//到达叶子节点
|
||||||
|
if(node.val==targetSum){
|
||||||
|
result.add(new ArrayList<>(cur));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
travel(node.left,targetSum- node.val);
|
||||||
|
travel(node.right,targetSum- node.val);
|
||||||
|
cur.remove(cur.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方最快:思路一样,可能快在使用数组进行增减
|
||||||
|
*/
|
||||||
|
private List<List<Integer>> ans = new ArrayList<>();
|
||||||
|
|
||||||
|
private void dfs(TreeNode root, int targetSum, int current, int[] node, int index) {
|
||||||
|
if( root == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node[index] = root.val;
|
||||||
|
current += root.val;
|
||||||
|
if( root.left == null && root.right == null ) {
|
||||||
|
if( current == targetSum ) {
|
||||||
|
List<Integer> result = new ArrayList<>();
|
||||||
|
for( int i = 0; i <= index; i++ ) {
|
||||||
|
result.add(node[i]);
|
||||||
|
}
|
||||||
|
ans.add(result);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dfs(root.left, targetSum, current, node, index + 1);
|
||||||
|
dfs(root.right, targetSum, current, node, index + 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getDepth(TreeNode root) {
|
||||||
|
if( root == null ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if( root.left == null && root.right == null ) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.max(getDepth(root.left), getDepth(root.right)) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<List<Integer>> pathSum1(TreeNode root, int targetSum) {
|
||||||
|
int depth = getDepth(root);
|
||||||
|
if( root == null ) {
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] node = new int[depth];
|
||||||
|
dfs(root, targetSum, 0, node, 0);
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
package com.markilue.leecode.tree.second;
|
||||||
|
|
||||||
|
import com.markilue.leecode.tree.TreeNode;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.tree.second
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2023-01-10 12:18
|
||||||
|
*@Description:
|
||||||
|
* TODO 二刷力扣106题 从中序与后序遍历序列构造二叉树:
|
||||||
|
* 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历,
|
||||||
|
* postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T14_BuildTree {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
int[] inorder = {9, 3, 15, 20, 7}, postorder = {9, 15, 7, 20, 3};
|
||||||
|
System.out.println(buildTree1(inorder,postorder));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:后续遍历的最后一个就是根节点,以此划分左右树,
|
||||||
|
* 自己被卡在就算划分了左右但是不知道inorder和postOrder应该怎么划分;
|
||||||
|
* 事实上两个个order一定一样长,可以根据中序定边界,从而划分两边
|
||||||
|
* 下属写法是最容易理解的写法,还有一些较为难理解但是传递索引而不是复制的写法来处理的写法,会比这个快
|
||||||
|
* 速度击败13.81%,内存击败15.72% 6ms
|
||||||
|
* @param inorder
|
||||||
|
* @param postorder
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TreeNode buildTree(int[] inorder, int[] postorder) {
|
||||||
|
int length = postorder.length;
|
||||||
|
if(length==0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TreeNode root = new TreeNode(postorder[length - 1]);
|
||||||
|
int boundary=0;
|
||||||
|
for (; boundary < inorder.length; boundary++) {
|
||||||
|
if(inorder[boundary]==postorder[length-1]){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int[] leftInorder = Arrays.copyOfRange(inorder, 0, boundary);
|
||||||
|
int[] rightInorder = Arrays.copyOfRange(inorder, boundary+1, length);
|
||||||
|
int[] leftPostorder = Arrays.copyOfRange(postorder, 0, boundary);
|
||||||
|
int[] rightPostorder = Arrays.copyOfRange(postorder, boundary, length - 1);
|
||||||
|
root.left=buildTree(leftInorder,leftPostorder);
|
||||||
|
root.right=buildTree(rightInorder,rightPostorder);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方最快
|
||||||
|
* 速度击败100%,内存击败72.96%
|
||||||
|
*/
|
||||||
|
int post,in;
|
||||||
|
public TreeNode buildTree1(int[] inorder, int[] postorder) {
|
||||||
|
post=inorder.length-1;
|
||||||
|
in=inorder.length-1;
|
||||||
|
return buildTreeHelper(inorder,postorder,Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
public TreeNode buildTreeHelper(int[] inorder, int[] postorder, int stop) {
|
||||||
|
if(post==-1)return null;
|
||||||
|
if(inorder[in]==stop){//stop是right边界,如果触及了右边界就那边就没有值了
|
||||||
|
in--;
|
||||||
|
return null;//找到了右边的边界
|
||||||
|
}
|
||||||
|
int root_val=postorder[post--];
|
||||||
|
TreeNode root = new TreeNode(root_val);
|
||||||
|
root.right=buildTreeHelper(inorder,postorder,root_val);
|
||||||
|
root.left=buildTreeHelper(inorder,postorder,stop);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue