leecode更新

This commit is contained in:
markilue 2023-01-12 14:44:45 +08:00
parent 64abd13286
commit 40313d9da9
15 changed files with 621 additions and 8 deletions

View File

@ -13,7 +13,7 @@ import java.util.*;
* 给定两个整数数组 inorder postorder 其中 inorder 是二叉树的中序遍历 postorder 是同一棵树的后序遍历请你构造并返回这颗二叉树 * 给定两个整数数组 inorder postorder 其中 inorder 是二叉树的中序遍历 postorder 是同一棵树的后序遍历请你构造并返回这颗二叉树
* @Version: 1.0 * @Version: 1.0
*/ */
public class T14_BuildTree { public class T14_0_BuildTree {
@Test @Test

View File

@ -13,7 +13,7 @@ import java.util.*;
* 给定两个整数数组preorder inorder其中preorder 是二叉树的先序遍历 inorder是同一棵树的中序遍历请构造二叉树并返回其根节点 * 给定两个整数数组preorder inorder其中preorder 是二叉树的先序遍历 inorder是同一棵树的中序遍历请构造二叉树并返回其根节点
* @Version: 1.0 * @Version: 1.0
*/ */
public class BuildTreeII { public class T14_1_BuildTreeII {
@Test @Test
public void test() { public void test() {

View File

@ -0,0 +1,154 @@
package com.markilue.leecode.tree;
import com.sun.scenario.effect.Brightpass;
import java.util.*;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.tree
*@Author: dingjiawen
*@CreateTime: 2023-01-11 11:14
*@Description:
* TODO 力扣654 最大二叉树:
* 给定一个不重复的整数数组 nums 最大二叉树 可以用下面的算法从 nums 递归地构建:
* 创建一个根节点其值为 nums 中的最大值
* 递归地在最大值 左边 子数组前缀上 构建左子树
* 递归地在最大值 右边 子数组后缀上 构建右子树
* 返回 nums 构建的 最大二叉树
*@Version: 1.0
*/
public class T14_2_ConstructMaximumBinaryTree {
/**
* 思路:这题实际上是给了一个中序遍历然后root的值由max确定
* 速度击败81.34%内存击败68.74% 2ms 时间复杂度O(n^2)
* @param nums
* @return
*/
public TreeNode constructMaximumBinaryTree(int[] nums) {
return constructTree(nums, 0, nums.length);
}
public TreeNode constructTree(int[] nums, int left, int right) {
if (left == right) {
return null;
}
int maxIndex = findMaxIndex(nums, left, right);
TreeNode root = new TreeNode(nums[maxIndex]);
root.left = constructTree(nums, left, maxIndex);
root.right = constructTree(nums, maxIndex + 1, right);
return root;
}
public int findMaxIndex(int[] nums, int left, int right) {
int maxIndex = left;
for (int i = left; i < right; i++) {
if (nums[maxIndex] < nums[i]) {
maxIndex = i;
}
}
return maxIndex;
}
/**
* 官方单调栈解法:
* 时间复杂度O(N)
* 速度击败5.7%内存击败82.36% 20ms
* @param nums
* @return
*/
public TreeNode constructMaximumBinaryTree1(int[] nums) {
int n = nums.length;
List<Integer> stack = new ArrayList<Integer>();
TreeNode[] tree = new TreeNode[n];
for (int i = 0; i < n; ++i) {
tree[i] = new TreeNode(nums[i]);
while (!stack.isEmpty() && nums[i] > nums[stack.get(stack.size() - 1)]) {
tree[i].left = tree[stack.get(stack.size() - 1)];
stack.remove(stack.size() - 1);
}
if (!stack.isEmpty()) {
tree[stack.get(stack.size() - 1)].right = tree[i];
}
stack.add(i);
}
return tree[stack.get(0)];
}
/**
* 官方单调栈容易理解版:
* TODO
* 核心在于维护一个单调栈这个栈单调递增
* 1)如果来的数大于栈里面的数,又因为来的数的索引i一定大于栈的数的索引所以栈里面的数的右边界应该是来的这个数(所以栈里数应该是来数的左子树)对应于while内容
* 2)如果来的数小于栈里面的数,又因为来的数的索引i一定大于栈的数的索引所以来的这个数的左边界应该是栈里面这个数(所以是栈里数的左子树)对应于if内容
* @param nums
* @return
*/
public TreeNode constructMaximumBinaryTree2(int[] nums) {
int n = nums.length;
Deque<Integer> stack = new ArrayDeque<Integer>();
int[] left = new int[n];
int[] right = new int[n];
Arrays.fill(left, -1);
Arrays.fill(right, -1);
TreeNode[] tree = new TreeNode[n];
for (int i = 0; i < n; ++i) {
tree[i] = new TreeNode(nums[i]);
while (!stack.isEmpty() && nums[i] > nums[stack.peek()]) {
right[stack.pop()] = i;
}
if (!stack.isEmpty()) {
left[i] = stack.peek();
}
stack.push(i);
}
TreeNode root = null;
for (int i = 0; i < n; ++i) {
if (left[i] == -1 && right[i] == -1) {
//最大的那个数,一定一直在栈里面所以left和right一定没有赴过值
root = tree[i];
} else if (right[i] == -1 || (left[i] != -1 && nums[left[i]] < nums[right[i]])) {
tree[left[i]].right = tree[i];//这个数的左边界的右子树应该是这个数
} else {
tree[right[i]].left = tree[i];
}
}
return root;
}
/**
* 官方最快:与本人思路一致
* @param nums
* @return
*/
public TreeNode constructMaximumBinaryTree3(int[] nums) {
return constructTree1(nums, 0, nums.length);
}
public TreeNode constructTree1(int[] nums, int leftIndex, int rightIndex) {
if (rightIndex - leftIndex < 1) {
return null;
}
if (rightIndex - leftIndex == 1) {
return new TreeNode(nums[leftIndex]);
}
int maxIndex = leftIndex;
int maxVal = nums[maxIndex];
for (int i = leftIndex + 1; i < rightIndex; i++) {
if (nums[i] > maxVal) {
maxVal = nums[i];
maxIndex = i;
}
}
TreeNode root = new TreeNode(maxVal);
root.left = constructTree1(nums, leftIndex, maxIndex);
root.right = constructTree1(nums, maxIndex + 1, rightIndex);
return root;
}
}

View File

@ -18,7 +18,7 @@ import java.util.*;
* 3返回合并后的二叉树 * 3返回合并后的二叉树
* @Version: 1.0 * @Version: 1.0
*/ */
public class MergeTrees { public class T15_MergeTrees {
@Test @Test
public void test() { public void test() {

View File

@ -12,7 +12,7 @@ import org.junit.Test;
* 你需要在 BST 中找到节点值等于val的节点 返回以该节点为根的子树 如果节点不存在则返回null * 你需要在 BST 中找到节点值等于val的节点 返回以该节点为根的子树 如果节点不存在则返回null
* @Version: 1.0 * @Version: 1.0
*/ */
public class SearchBST { public class T16_SearchBST {
@Test @Test
public void test() { public void test() {

View File

@ -17,7 +17,7 @@ import java.util.Stack;
* 3.所有左子树和右子树自身必须也是二叉搜索树 * 3.所有左子树和右子树自身必须也是二叉搜索树
* @Version: 1.0 * @Version: 1.0
*/ */
public class IsValidBST { public class T17_IsValidBST {
@Test @Test
public void test() { public void test() {

View File

@ -14,7 +14,7 @@ import java.util.Stack;
* 差值是一个正数其数值等于两值之差的绝对值 * 差值是一个正数其数值等于两值之差的绝对值
* @Version: 1.0 * @Version: 1.0
*/ */
public class GetMinimumDifference { public class T18_GetMinimumDifference {
@Test @Test
public void test() { public void test() {

View File

@ -19,7 +19,7 @@ import java.util.*;
* 左子树和右子树都是二叉搜索树 * 左子树和右子树都是二叉搜索树
* @Version: 1.0 * @Version: 1.0
*/ */
public class FindMode { public class T19_FindMode {
@Test @Test

View File

@ -16,7 +16,7 @@ import java.util.Arrays;
* postorder 是同一棵树的后序遍历请你构造并返回这颗 二叉树 * postorder 是同一棵树的后序遍历请你构造并返回这颗 二叉树
*@Version: 1.0 *@Version: 1.0
*/ */
public class T14_BuildTree { public class T14_0_BuildTree {
@Test @Test
public void test(){ public void test(){

View File

@ -0,0 +1,92 @@
package com.markilue.leecode.tree.second;
import com.markilue.leecode.tree.TreeNode;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.tree.second
*@Author: dingjiawen
*@CreateTime: 2023-01-11 10:03
*@Description:
* TODO 力扣105题 从前序与中序遍历序列构造二叉树:
* 给定两个整数数组 preorder inorder
* 其中 preorder 是二叉树的先序遍历 inorder 是同一棵树的中序遍历
* 请构造二叉树并返回其根节点
*@Version: 1.0
*/
public class T14_1_BuildTreeII {
@Test
public void test() {
int[] inorder = {9, 3, 15, 20, 7}, preorder = {3, 9, 20, 15, 7};
System.out.println(buildTree(preorder, inorder));
}
/**
* 思路:T14_0类似只不过这里是从头开始找root
* 速度击败43.48%内存击败80.45% 3ms
* @param preorder
* @param inorder
* @return
*/
public TreeNode buildTree(int[] preorder, int[] inorder) {
return build(preorder, inorder, 0, preorder.length, 0, inorder.length);
}
public TreeNode build(int[] preorder, int[] inorder, int preLeft, int preRight, int inLeft, int inRight) {
int length = preRight - preLeft;
if (length == 0) {
return null;
}
TreeNode root = new TreeNode(preorder[preLeft]);
int boundary = inLeft;
for (; boundary < inRight; boundary++) {
if (inorder[boundary] == root.val) {
break;
}
}
boundary = boundary - inLeft;
root.left = build(preorder, inorder, preLeft + 1, preLeft + 1 + boundary, inLeft, inLeft + boundary);
root.right = build(preorder, inorder, preLeft + 1 + boundary, preRight, inLeft + boundary + 1, inRight);
return root;
}
/**
* 官方最快:思路类似可能快在不传pre的直接通过i++来获取
* 速度击败100%内存击败53.29% 0ms
*/
public int i = 0;
public TreeNode buildTree1(int[] preorder, int[] inorder) {
TreeNode root = buildTreeChild(preorder, inorder, 0, inorder.length - 1);
return root;
}
public TreeNode buildTreeChild(int[] preorder, int[] inorder,
int inbegin, int inend) {
if (inbegin > inend) {
return null;
}
TreeNode root = new TreeNode(preorder[i]);
//找到当前根在中序遍历的位置
int rootIndex = findIndex(inorder, inbegin, inend, preorder[i]);
i++;
root.left = buildTreeChild(preorder, inorder, inbegin, rootIndex - 1);
root.right = buildTreeChild(preorder, inorder, rootIndex + 1, inend);
return root;
}
private int findIndex(int[] inorder, int inbegin, int end, int key) {
int rootIndex = 0;
while (end >= inbegin) {
if (inorder[end] == key) {
return end;
}
end--;
}
return -1;
}
}

View File

@ -0,0 +1,69 @@
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-11 12:11
*@Description:
* TODO 力扣617题 合并二叉树:
* 给你两棵二叉树 root1 root2
* 想象一下当你将其中一棵覆盖到另一棵之上时两棵树上的一些节点将会重叠而另一些不会
* 你需要将这两棵树合并成一棵新二叉树合并的规则是
* 如果两个节点重叠那么将这两个节点的值相加作为合并后节点的新值
* 否则不为 null 的节点将直接作为新二叉树的节点
* 返回合并后的二叉树
* 注意: 合并过程必须从两个树的根节点开始
*@Version: 1.0
*/
public class T15_MergeTrees {
/**
* 思路:递归法
* 速度击败100%内存击败35.5%
* @param root1
* @param root2
* @return
*/
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
TreeNode root;
if (root1 == null && root2 == null) {
return null;
} else if (root1 == null) {
root= new TreeNode(root2.val);
root.left=mergeTrees(null,root2.left);
root.right=mergeTrees(null,root2.right);
} else if (root2 == null) {
root = new TreeNode(root1.val);
root.left=mergeTrees(root1.left,null);
root.right=mergeTrees(root1.right,null);
} else {
root = new TreeNode(root1.val+root2.val);
root.left=mergeTrees(root1.left,root2.left);
root.right=mergeTrees(root1.right,root2.right);
}
return root;
}
/**
* 自己以前写的优秀写法
* @param root1
* @param root2
* @return
*/
public TreeNode mergeTrees1(TreeNode root1, TreeNode root2) {
if (root1 == null) {
return root2;
} else {
if (root2 != null) {
root1.val = root1.val + root2.val;
root1.left=mergeTrees1(root1.left,root2.left);
root1.right=mergeTrees1(root1.right,root2.right);
}
return root1;
}
}
}

View File

@ -0,0 +1,66 @@
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-12 12:11
*@Description:
* TODO 二刷题700 二叉搜索树中的搜索:
* 给定二叉搜索树BST的根节点 root 和一个整数值 val
* 你需要在 BST 中找到节点值等于 val 的节点 返回以该节点为根的子树 如果节点不存在则返回 null
*@Version: 1.0
*/
public class T16_SearchBST {
/**
* 思路利用二叉搜索树的特性
* 递归法 速度击败100%内存击败16.67%
* @param root
* @param val
* @return
*/
public TreeNode searchBST(TreeNode root, int val) {
if(root==null){
return null;
}
if(root.val==val){
return root;
}else if(root.val<val){
return searchBST(root.right, val);
}else {
return searchBST(root.left,val);
}
}
/**
* 思路利用二叉搜索树的特性
* 迭代法 速度击败100%内存击败16.67%
* @param root
* @param val
* @return
*/
public TreeNode searchBST1(TreeNode root, int val) {
if(root==null){
return null;
}
TreeNode cur=root;
while (cur!=null){
if(cur.val==val){
return cur;
}else if(cur.val>val){
cur=cur.left;
}else {
cur=cur.right;
}
}
return cur;
}
}

View File

@ -0,0 +1,86 @@
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-12 12:27
*@Description:
* TODO 二刷力扣98题 验证二叉搜索树:
* 给你一个二叉树的根节点 root 判断其是否是一个有效的二叉搜索树
* 有效 二叉搜索树定义如下
* 节点的左子树只包含 小于 当前节点的数
* 节点的右子树只包含 大于 当前节点的数
* 所有左子树和右子树自身必须也是二叉搜索树
*@Version: 1.0
*/
public class T17_IsValidBST {
@Test
public void test(){
System.out.println(Integer.MAX_VALUE);
}
/**
* 思路:需要注意不是左右子树满足就行而是整个左右子树都需要满足
* 速度击败100%内存击败85.63%
* @param root
* @return
*/
public boolean isValidBST(TreeNode root) {
return isValid(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
/**
* 当前节点需要满足左右边界
* @param root
* @param leftThreshold
* @param rightThreshold
* @return
*/
public boolean isValid(TreeNode root, long leftThreshold, long rightThreshold) {
if (root == null) {
return true;
}
if (root.val <= leftThreshold || root.val >= rightThreshold) {
return false;
}
return isValid(root.left, leftThreshold, root.val) && isValid(root.right, root.val, rightThreshold);
}
/**
* 递归法中序遍历即可前面的节点一定要小于当前的节点即可
* 速度击败19.10%,内存击败13.11%
* @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;
pre = cur;//保存访问的前一个节点
cur = cur.right;
}
}
return true;
}
}

View File

@ -0,0 +1,69 @@
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-12 12:46
*@Description:
* TODO 力扣530 二叉搜索树的最小绝对差:
* 给你一个二叉搜索树的根节点 root 返回 树中任意两不同节点值之间的最小差值
* 差值是一个正数其数值等于两值之差的绝对值
*@Version: 1.0
*/
public class T18_GetMinimumDifference {
/**
* 思路:二叉搜索树特性决定了最小绝对差一定是两个连续中序遍历节点的差值
* 速度击败100%内存击败77.8%
* @param root
* @return
*/
int min=Integer.MAX_VALUE;
TreeNode pre=null;
public int getMinimumDifference(TreeNode root) {
travel(root);
return min;
}
public void travel(TreeNode root) {
if(root==null){
return;
}
travel(root.left);
if(pre!=null&&min>root.val-pre.val){
min=root.val-pre.val;
}
pre=root;
travel(root.right);
}
/**
* 迭代法,仍然是中序遍历,实际上与上面的递归无差异
*/
Stack<TreeNode> stack;
public int getMinimumDifference1(TreeNode root) {
if (root == null) return 0;
stack = new Stack<>();
TreeNode cur = root;
int result = Integer.MAX_VALUE;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur); // 将访问的节点放进栈
cur = cur.left; //
}else {
cur = stack.pop();
if (pre != null) { //
result = Math.min(result, cur.val - pre.val);
}
pre = cur;
cur = cur.right; //
}
}
return result;
}
}

View File

@ -0,0 +1,77 @@
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-12 13:05
*@Description:
* TODO 力扣501 二叉搜索树中的众数:
* 给你一个含重复值的二叉搜索树BST的根节点 root 找出并返回 BST 中的所有 众数出现频率最高的元素
* 如果树中有不止一个众数可以按 任意顺序 返回
* 假定 BST 满足如下定义
* 结点左子树中所含节点的值 小于等于 当前节点的值
* 结点右子树中所含节点的值 大于等于 当前节点的值
* 左子树和右子树都是二叉搜索树
*@Version: 1.0
*/
public class T19_FindMode {
/**
* 思路:由于二叉搜索树的中序遍历的特性,相同的数应该是连在一起的
* 速度击败100%内存击败85.48%
* @param root
* @return
*/
TreeNode pre = null;
int maxTime = 0;
int curTime = 0;
List<Integer> result = new ArrayList<>();
public int[] findMode(TreeNode root) {
find(root);
//最后一次如果相等就还是不会进
if (maxTime == curTime) {
result.add(pre.val);
} else if (maxTime < curTime) {
maxTime = curTime;
result.clear();
result.add(pre.val);
}
int[] nums = new int[result.size()];
for (int i = 0; i < nums.length; i++) {
nums[i]=result.get(i);
}
return nums;
}
public void find(TreeNode root) {
if (root == null) {
return;
}
find(root.left);
if (pre == null || pre.val == root.val) {
curTime++;
}else {
if (maxTime == curTime) {
result.add(pre.val);
} else if (maxTime < curTime) {
maxTime = curTime;
result.clear();
result.add(pre.val);
}
curTime = 1;
}
pre=root;
find(root.right);
}
}