leecode更新

This commit is contained in:
markilue 2023-03-10 22:17:42 +08:00
parent 1e6629760f
commit 09e3ac8282
7 changed files with 752 additions and 0 deletions

View File

@ -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<Integer> cur = new ArrayList<>();
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> 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);
}
}
}
}

View File

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

View File

@ -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<Integer> mono_stack = new ArrayDeque<Integer>();
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;
}
}

View File

@ -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<Integer> stack = new LinkedList<Integer>();
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;
}
}
}

View File

@ -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<Integer> inorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
List<Integer> 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<Integer> inorderTraversal1(TreeNode root) {
TreeNode cur = root;
List<Integer> 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;
}
}

View File

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

View File

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