From 09e3ac8282d052ef68e9011c3130c22e6a750302 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Fri, 10 Mar 2023 22:17:42 +0800 Subject: [PATCH] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../markilue/leecode/hot100/T36_Subsets.java | 56 ++++++ .../markilue/leecode/hot100/T37_Exist.java | 174 ++++++++++++++++++ .../hot100/T38_LargestRectangleArea.java | 156 ++++++++++++++++ .../leecode/hot100/T39_MaximalRectangle.java | 124 +++++++++++++ .../leecode/hot100/T40_inorderTraversal.java | 104 +++++++++++ .../markilue/leecode/hot100/T41_NumTrees.java | 46 +++++ .../leecode/hot100/T42_IsValidBST.java | 92 +++++++++ 7 files changed, 752 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T36_Subsets.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T37_Exist.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T38_LargestRectangleArea.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T39_MaximalRectangle.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T40_inorderTraversal.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T41_NumTrees.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T42_IsValidBST.java diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T36_Subsets.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T36_Subsets.java new file mode 100644 index 0000000..9ae4d3f --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T36_Subsets.java @@ -0,0 +1,56 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-09 10:18 + *@Description: + * TODO 力扣78题 子集: + * 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。 + * 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 + *@Version: 1.0 + */ +public class T36_Subsets { + + @Test + public void test() { + int[] nums = {1, 2, 3}; + System.out.println(subsets(nums)); + } + + + List cur = new ArrayList<>(); + List> result = new ArrayList<>(); + + public List> subsets(int[] nums) { + backtracking(nums, 0); + return result; + } + + public void backtracking(int[] nums, int start) { + if (nums.length == start) { + result.add(new ArrayList<>(cur)); + return; + } + + for (int i = 0; i < 2; i++) { + if(i==0){ + backtracking(nums, start + 1); + }else { + cur.add(nums[start]); + backtracking(nums, start + 1); + cur.remove(cur.size() - 1); + } + + } + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T37_Exist.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T37_Exist.java new file mode 100644 index 0000000..bbc5f4a --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T37_Exist.java @@ -0,0 +1,174 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-09 10:37 + *@Description: + * TODO 力扣79题 单词搜索: + * 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 + * 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。 + *@Version: 1.0 + */ +public class T37_Exist { + + @Test + public void test() { + char[][] board = {{'A', 'B', 'C', 'E'}, {'S', 'F', 'C', 'S'}, {'A', 'D', 'E', 'E'}}; + String word = "ABCCED"; + System.out.println(exist(board, word)); + } + + @Test + public void test1() { + char[][] board = {{'A', 'B', 'C', 'E'}, {'S', 'F', 'C', 'S'}, {'A', 'D', 'E', 'E'}}; + String word = "SEE"; + System.out.println(exist(board, word)); + } + + + @Test + public void test2() { + char[][] board = {{'a'}}; + String word = "a"; + System.out.println(exist(board, word)); + } + StringBuilder cur = new StringBuilder(); + + + /** + * 思路:回溯:开头加for是因为需要以每一个当开头都试一下,比价麻烦 + * 速度击败14.16% 内存击败57.17% 271ms + * @param board + * @param word + * @return + */ + public boolean exist(char[][] board, String word) { + + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if(backtracking(board, word, i, j, new boolean[board.length][board[0].length])){ + return true; + } + } + } + return false; + } + + public boolean backtracking(char[][] board, String word, int i, int j, boolean[][] used) { + if (cur.length() == word.length()) { + if (word.equals(cur.toString())) { + return true; + } + return false; + } + if (i >= board.length || j >= board[0].length || i < 0 || j < 0||used[i][j]) { + //索引越界 或者 被用过 + return false; + } + if (board[i][j] != word.charAt(cur.length())) {//只有相等才继续 + return false; + } + + + cur.append(board[i][j]); + used[i][j] = true; + for (int k = 0; k < 4; k++) { + + boolean flag = false; + if (k == 0) { + flag = backtracking(board, word, i, j + 1, used); + } else if (k == 1) { + flag = backtracking(board, word, i + 1, j, used); + } else if (k == 2) { + flag = backtracking(board, word, i, j - 1, used); + } else { + flag = backtracking(board, word, i - 1, j, used); + } + if (flag) { + return true; + } + } + used[i][j] = false; + cur.deleteCharAt(cur.length() - 1); + + + return false; + } + + + /** + * 官方最快:使用了很多优化手段 + * 不用使用cur去记录了,而是直接使用index来判断当前比对到哪里了 + * 从而避免了大量的回溯;同时也不再使用for循环,而是全在if里面 + * 速度击败100% 内存击败52.42% 0ms + * @param board + * @param word + * @return + */ + public boolean exist1(char[][] board, String word) { + + boolean[][]used = new boolean[board.length][board[0].length]; + char[] chars = word.toCharArray(); + // dfs优化加速:如果满足头部字符比较多,那就反转wordArray,从尾部开始dfs + int len = chars.length; + int head = 0; + + //判断等于头部的多还是尾部的多 + for (char[] row : board) { + for (char ch : row) { + if (ch == chars[0]) { + head++; + } else if (ch == chars[len - 1]) { + head--; + } + } + } + //头多就交换为尾多 + if (head > 0) { + // reverse + int l = 0; + int r = len - 1; + while (l < r) { + char temp = chars[r]; + chars[r] = chars[l]; + chars[l] = temp; + l++; + r--; + } + } + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if (exist(i, j, 0, board, chars, used)) { + return true; + } + } + } + return false; + } + + public boolean exist(int i, int j, int index,char[][] board, char[] word, boolean[][]used) { + if (i == board.length || j == board[0].length || i < 0 || j < 0) { + return false; + } + if (board[i][j] == word[index] && !used[i][j]) { + //这里传参index去避免回溯 + if (++ index == word.length) { + return true; + } + used[i][j] = true; + if (exist(i, j + 1, index, board, word, used) + || exist(i + 1, j, index, board, word, used) + || exist(i, j - 1, index, board, word, used) + || exist(i - 1, j, index, board, word, used)) { + return true; + } + used[i][j] = false; + + } + return false; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T38_LargestRectangleArea.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T38_LargestRectangleArea.java new file mode 100644 index 0000000..746da5c --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T38_LargestRectangleArea.java @@ -0,0 +1,156 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.ArrayDeque; +import java.util.Deque; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-10 09:57 + *@Description: + * TODO 力扣84题 柱状图中最大的矩形: + * 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 + * 求在该柱状图中,能够勾勒出来的矩形的最大面积。 + *@Version: 1.0 + */ +public class T38_LargestRectangleArea { + + @Test + public void test() { + int[] height = {2, 1, 5, 6, 2, 3}; + System.out.println(largestRectangleArea(height)); + } + + @Test + public void test1() { + int[] height = {9, 0}; + System.out.println(largestRectangleArea(height)); + } + + @Test + public void test2() { + int[] height = {6,7,5,2,4,5,9,3}; + System.out.println(largestRectangleArea1(height)); + } + + /** + * 思路:感觉和接雨水很像,只不过一个是要找总量比他少的 + * 尝试使用双指针法 + * 尚且有问题 + * @param heights + * @return + */ + public int largestRectangleArea(int[] heights) { + if (heights.length == 1) { + return heights[0]; + } + + int left = heights.length >> 1; + int right = left; + int leftMin = Integer.MAX_VALUE; + int rightMin = Integer.MAX_VALUE; + int maxArea = 0; + int curArea = 0; + + while (left >= 0 && right < heights.length) { + leftMin = Math.min(heights[left], leftMin); + rightMin = Math.min(heights[right], rightMin); + curArea = Math.min(leftMin, rightMin) * (right - left + 1); + if (maxArea < curArea) maxArea = curArea; + if (left == 0 || heights[left] < heights[right]) {//矮的人放心左移 + right++; + } else { + left--; + } + + } + + //忽略了每个单一的情况 + for (int i = 0; i < heights.length; i++) { + if (heights[i] > maxArea) maxArea = heights[i]; + } + + return maxArea; + + } + + + /** + * TODO 官方单调栈解法:具体可以看笔记 + * 1)首先我们枚举某一根柱子 iii 作为高 h=heights[i] + * 2)随后我们需要进行向左右两边扩展,使得扩展到的柱子的高度均不小于 h。 + * 换句话说,我们需要找到左右两侧最近的高度小于 h 的柱子,这样这两根柱子之间(不包括其本身)的所有柱子高度均不小于 h, + * 并且就是 i能够扩展到的最远范围。 + * 本质上就是寻找两边单调最大的值 + * 速度击败44.82% 内存击败9.7% 30ms + * TDOO 本质上就是记录以当前高为基础,最多能扩展左右到哪里,再用当前高*最多扩展 + * @param heights + * @return + */ + public int largestRectangleArea1(int[] heights) { + int n = heights.length; + int[] left = new int[n]; + int[] right = new int[n]; + + Deque mono_stack = new ArrayDeque(); + for (int i = 0; i < n; ++i) { + while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) { + mono_stack.pop(); + } + left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek()); + mono_stack.push(i); + } + + mono_stack.clear(); + for (int i = n - 1; i >= 0; --i) { + while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) { + mono_stack.pop(); + } + right[i] = (mono_stack.isEmpty() ? n : mono_stack.peek()); + mono_stack.push(i); + } + + int ans = 0; + for (int i = 0; i < n; ++i) { + ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]); + } + return ans; + } + + + /** + * 官方最快,常数空间优化 + * 速度击败100% 内存击败85.54% 4ms + * @param heights + * @return + */ + public int largestRectangleArea2(int[] heights) { + int len = heights.length; + int[] index = new int[len + 1]; + int[] stack = new int[len + 1]; + int top = 0; + int result = 0; + + for (int i = 0; i < len; i++) { + while (top > 0 && stack[top] > heights[i]) { + int height = stack[top]; + while (height == stack[--top]) { + } + result = Math.max(result, height * (i - index[top])); + } + stack[++top] = heights[i]; + index[top] = i + 1; + } + while (stack[top] > 0) { + int height = stack[top]; + while (height == stack[--top]) { + } + result = Math.max(result, height * (len - index[top])); + } + return result; + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T39_MaximalRectangle.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T39_MaximalRectangle.java new file mode 100644 index 0000000..a0eed3f --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T39_MaximalRectangle.java @@ -0,0 +1,124 @@ +package com.markilue.leecode.hot100; + +import java.util.Deque; +import java.util.LinkedList; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-10 13:43 + *@Description: + * TODO 力扣85题 最大矩形: + * 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。 + *@Version: 1.0 + */ +public class T39_MaximalRectangle { + + /** + * 思路:当前位置能不能和其他地方连起来取决于 左一块是不是1和上1块是不是1 + * TODO 官方解法 : 本质上于T38类似,可以使用单调栈解法 就是在T38的基础上再加了一个列级的for循环 + * 速度击败48.24% 内存击败77.7% 16ms + * @param matrix + * @return + */ + public int maximalRectangle(char[][] matrix) { + int m = matrix.length; + if (m == 0) { + return 0; + } + int n = matrix[0].length; + int[][] left = new int[m][n]; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (matrix[i][j] == '1') { + left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1; + } + } + } + + int ret = 0; + for (int j = 0; j < n; j++) { // 对于每一列,使用基于柱状图的方法 + int[] up = new int[m]; + int[] down = new int[m]; + + Deque stack = new LinkedList(); + for (int i = 0; i < m; i++) { + while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) { + stack.pop(); + } + up[i] = stack.isEmpty() ? -1 : stack.peek(); + stack.push(i); + } + stack.clear(); + for (int i = m - 1; i >= 0; i--) { + while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) { + stack.pop(); + } + down[i] = stack.isEmpty() ? m : stack.peek(); + stack.push(i); + } + + for (int i = 0; i < m; i++) { + int height = down[i] - up[i] - 1; + int area = height * left[i][j]; + ret = Math.max(ret, area); + } + } + return ret; + } + + + /** + * 官方最快:本质上与上面的一致,不知道为啥快 + * 速度击败100% 内存击败55.97% 1ms + * @param matrix + * @return + */ + public int maximalRectangle1(char[][] matrix) { + int[] heights = new int[matrix[0].length]; + int max = 0; + for (int i = 0; i < matrix.length; i++) { + updateHeights(heights, matrix[i]); + + max = Math.max(max, largestRectangleArea(heights)); + } + + return max; + } + + private int largestRectangleArea(int[] heights) { + int len = heights.length; + int max = 0; + int[] stack = new int[len]; + int k = -1; + for (int r = 0; r < len; r++) { + while (k != -1 && heights[stack[k]] > heights[r]) { + int low = stack[k--]; + int l = k == -1 ? -1 : stack[k]; + max = Math.max(max, (r - 1 - l) * heights[low]); + } + stack[++k] = r; + } + while (k != -1) { + int low = stack[k--]; + int l = k == -1 ? -1 : stack[k]; + max = Math.max(max, (len - 1 - l) * heights[low]); + } + + return max; + } + + public void updateHeights(int[] heights, char[] cells) { + for (int j = 0; j < heights.length; j++) { + heights[j] = cells[j] == '0' ? 0 : heights[j] + 1; + } + } + + + + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T40_inorderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T40_inorderTraversal.java new file mode 100644 index 0000000..756a12c --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T40_inorderTraversal.java @@ -0,0 +1,104 @@ +package com.markilue.leecode.hot100; + +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; +import java.util.Stack; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-10 14:35 + *@Description: + * TODO 力扣94题 二叉树的中序遍历: + * 给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。 + *@Version: 1.0 + */ +public class T40_inorderTraversal { + + + @Test + public void test() { + + TreeNode root = TreeUtils.structureTree(Arrays.asList(1, null, 2,null,null, 3), 0); + System.out.println(inorderTraversal1(root)); + } + + + /** + * 思路:stack栈法 + * 速度击败100% 内存击败20.99% 0ms + * @param root + * @return + */ + public List inorderTraversal(TreeNode root) { + + Stack stack = new Stack<>(); + + TreeNode cur = root; + List result = new ArrayList<>(); + + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + stack.push(cur); + cur = cur.left; + } else { + TreeNode node = stack.pop(); + result.add(node.val); + cur = node.right; + } + } + + return result; + + } + + + /** + * morris遍历 + * 速度击败100% 内存击败21.68% + * @param root + * @return + */ + public List inorderTraversal1(TreeNode root) { + + TreeNode cur = root; + List result = new ArrayList<>(); + + while (cur != null) { + if (cur.left != null) { + TreeNode left = cur.left; + + //寻找他左节点的最右节点 + while (left.right != null && left.right != cur) { + left = left.right; + } + + //判断是从什么条件出来的 + if (left.right == null) { + left.right = cur; + //放心将cur左移 + cur = cur.left; + } else { + //第二次遍历到了,可以加入 + result.add(cur.val); + cur = cur.right; + left.right = null;//防止下次再来 + } + } else { + //第二次遍历到了,可以加入 + result.add(cur.val); + cur = cur.right; + } + } + + return result; + + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T41_NumTrees.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T41_NumTrees.java new file mode 100644 index 0000000..29503c3 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T41_NumTrees.java @@ -0,0 +1,46 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-10 15:07 + *@Description: + * TODO 力扣96题 不同的二叉搜索树: + * 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 + *@Version: 1.0 + */ +public class T41_NumTrees { + + @Test + public void test(){ + System.out.println(numTrees(3)); + } + + + /** + * 思路: n等于几 就是分别代表使用1-n为根节点的情况之后 + * 速度击败100% 内存击败93.62% 0ms + * @param n + * @return + */ + public int numTrees(int n) { + if (n < 3) return n; + + int[] dp = new int[n + 1]; + dp[0] = 1; + dp[1] = 1; + + for (int i = 3; i < dp.length; i++) { + //分别以1为底-i为底之和 + for (int j = 1; j <= i; j++) { + dp[i] += dp[j - 1] * dp[i - j]; + } + } + + return dp[n]; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T42_IsValidBST.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T42_IsValidBST.java new file mode 100644 index 0000000..ac5b885 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T42_IsValidBST.java @@ -0,0 +1,92 @@ +package com.markilue.leecode.hot100; + +import com.markilue.leecode.tree.TreeNode; +import com.markilue.leecode.tree.TreeUtils; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Scanner; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-10 15:20 + *@Description: + * TODO 力扣98题 验证二叉搜索树: + * 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。 + * 有效 二叉搜索树定义如下: + * 节点的左子树只包含 小于 当前节点的数。 + * 节点的右子树只包含 大于 当前节点的数。 + * 所有左子树和右子树自身必须也是二叉搜索树。 + *@Version: 1.0 + */ +public class T42_IsValidBST { + + @Test + public void test() { +// TreeNode root = TreeUtils.structureTree(Arrays.asList(5, 1, 4, null, null, 3, 6), 0); + TreeNode root = TreeUtils.structureTree(Arrays.asList(2,1,3), 0); + System.out.println(isValidBST(root)); + } + + /** + * 思路:深度优先,从下往上确定范围 + * @param root + * @return + */ + public boolean isValidBST(TreeNode root) { + return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE); + } + + + public boolean isValidBST(TreeNode root, long leftThreshold, long rightThreshold) { + if (root == null) { + return true; + } + + boolean left = isValidBST(root.left, leftThreshold, root.val); + if (!left) { + return false; + } + boolean right = isValidBST(root.right, root.val, rightThreshold); + + if (!right) { + return false; + } + + return root.val > leftThreshold && root.val < rightThreshold; + + + } + + + @Test + public void test4(){ + Scanner sc = new Scanner(System.in); + + int count = sc.nextInt(); + + while(count-->0){ + int a = sc.nextInt(); + int b = sc.nextInt(); + System.out.println(a+b); + } + } + + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + +// int count = sc.nextInt(); + String[] s = sc.nextLine().split(" "); + int[] a=new int[s.length]; + + int res = Arrays.stream(s).mapToInt(Integer::parseInt).sum(); + + System.out.println(res); + + + + } +}