leecode更新

This commit is contained in:
markilue 2023-03-31 15:06:24 +08:00
parent e6858db144
commit ebbaae5e7f
9 changed files with 758 additions and 63 deletions

View File

@ -9,6 +9,33 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<artifactId>DataStructures</artifactId>
<build>
<plugins>

View File

@ -0,0 +1,73 @@
package com.atguigu.sort.selftry;
import org.junit.Test;
import java.util.Arrays;
/**
*@BelongsProject: DataStructures_Algorithm
*@BelongsPackage: com.atguigu.sort.selftry
*@Author: markilue
*@CreateTime: 2023-03-31 10:26
*@Description: TODO 尝试堆排序
*@Version: 1.0
*/
public class HeapSort {
@Test
public void test(){
int[] arr = {20, 50, 45, 40, 35,10,30,15,25};
//测试80000个数据进行测试
// int[] arr = new int[200];
// for (int i = 0; i < arr.length; i++) {
// arr[i] = (int) (Math.random() * 200); //生成一个[0,80000]的数
// }
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
public void heapSort(int[] arr) {
if (arr == null) return;
//从最后一个非叶子节点开始进行堆化
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, arr.length);
}
//进行交换
int temp;
for (int i = arr.length - 1; i > 0; i--) {
temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
adjustHeap(arr, 0, i);//把交换完的i放在合适的位置
}
}
public void adjustHeap(int[] arr, int i, int length) {
int temp = arr[i];//记录下以前位置的值
for (int j = 2 * i + 1; j < length; j++) {
//比较左右节点哪一个更大
if (j + 1 < length && arr[j] < arr[j + 1]) {
j++;
}
if (arr[j] > temp) {
//需要进行交换
arr[i] = arr[j];
i = j;//后续比较j位置的值了
} else {
break;
}
}
arr[i] = temp;//找到合适的位置放temp
}
}

View File

@ -1,5 +1,7 @@
package com.atguigu.tree;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
@ -17,44 +19,57 @@ public class HeapSort {
// System.out.println(Arrays.toString(arr));
//测试80000个数据进行测试
int[] arr =new int[8000000];
int[] arr = new int[8000000];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int)(Math.random()*8000000); //生成一个[0,80000]的数
arr[i] = (int) (Math.random() * 8000000); //生成一个[0,80000]的数
}
Date date1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(date1);
System.out.println("排序前的时间:"+date1Str); //排序前的时间:2022-02-15 21:19:36
System.out.println("排序前的时间:" + date1Str); //排序前的时间:2022-02-15 21:19:36
heapSort(arr);
Date date2 = new Date();
String date2Str = simpleDateFormat.format(date2);
System.out.println("排序后的时间:"+date2Str); //排序后的时间:2022-02-15 21:19:40
System.out.println("排序后的时间:" + date2Str); //排序后的时间:2022-02-15 21:19:40
}
@Test
public void test() {
int[] arr = {20, 50, 45, 40, 35,10,30,15,25};
//测试80000个数据进行测试
// int[] arr = new int[200];
// for (int i = 0; i < arr.length; i++) {
// arr[i] = (int) (Math.random() * 200); //生成一个[0,80000]的数
// }
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
/**
* 编写一个堆排序的方法
*/
public static void heapSort(int[] arr) {
//TODO (1)将无序序列构建成一个堆,根据升序降序需求选择大顶堆或者小顶堆
//arr.length/2-1求出来的是完全二叉树的最后一个非叶子节点
for (int i = arr.length/2-1; i >= 0; i--) {
adjustHeap(arr,i,arr.length);
// arr.length/2-1求出来的是完全二叉树的最后一个非叶子节点;
// arr.length/2-1是关键是adjustHeap前提的满足条件的前提
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, arr.length);
}
int temp=0;
int temp = 0;
//TODO (2)将顶对元素与末尾元素交换,将最大元素放置在数组末尾
//TODO (3)重新调整结构,使其满足堆定义,然后继续交换对顶元素与当前末尾元素,贩毒执行调整+交换步骤,直到整个序列有序
for (int i = arr.length-1; i >0; i--) {
//TODO (3)重新调整结构,使其满足堆定义,然后继续交换对顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序
for (int i = arr.length - 1; i > 0; i--) {
//交换
temp=arr[i];
arr[i]=arr[0];
arr[0]=temp;
adjustHeap(arr,0,i);
temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
adjustHeap(arr, 0, i);//主要就是利用堆顶元素就是最大值来进行处理的
}
@ -62,7 +77,7 @@ public class HeapSort {
}
/**
* 前提:该节点的所有子节点都已经是大顶堆了
* TODO 前提:该节点的所有子节点都已经是大顶堆了因为这里需要break
* 将以第i个位置为根节点时以下树,调整成一个大顶堆
*
* @param arr 待调整的数组
@ -76,20 +91,22 @@ public class HeapSort {
//开始调整
//说明:j = i * 2 + 1 ;这里k就是i节点的左子节点
for (int j = i * 2 + 1; j < length; j = j * 2 + 1) {
//TODO 1.寻找左右节点哪一个更大
if (j + 1 < length && arr[j] < arr[j + 1]) {
//左子节点的值小于右子节点的值
j++; //j指向右子节点
}
//TODO 2.用左右节点中大值去和他的父节点比较如果小了直接将父节点变成那个最大的值
if (arr[j] > temp) {
//如果子节点大于父节点
arr[i] = arr[j];//把较大的值赋给当前节点
i = j; //将i指向j继续循环比较
}else {
break;
} else {
break;//左右子节点都比父节点小直接break
}
}
//当for循环结束后,我们已经将以i为父节点的树的最大值,放在了i的位置
arr[i]=temp; //将temp值放在调整后的位置
arr[i] = temp; //将temp值放在调整后的位置
}

View File

@ -0,0 +1,72 @@
package com.markilue.leecode.hot100;
import org.junit.Test;
import java.util.Arrays;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hot100
*@Author: markilue
*@CreateTime: 2023-03-30 10:14
*@Description:
* TODO 力扣300 最长递增子序列:
* 给你一个整数数组 nums 找到其中最长严格递增子序列的长度
* 子序列 是由数组派生而来的序列删除或不删除数组中的元素而不改变其余元素的顺序例如[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列
*@Version: 1.0
*/
public class T78_LengthOfLIS {
@Test
public void test() {
// int[] nums={10,9,2,5,3,7,101,18};
int[] nums = {1, 3, 6, 7, 9, 4, 10, 5, 6};
System.out.println(lengthOfLIS(nums));
}
/**
* 思路:dp
* dp[i]表示以0开头以i结尾的数组的最长递增子序列长度
* @param nums
* @return
*/
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
int max = 0;
for (int i = 1; i < dp.length; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
if (max < dp[i]) max = dp[i];
}
}
return max;
}
public int lengthOfLIS1(int[] nums) {
int N = nums.length;
//end[i]表示i+1长度的递增子序列的最小值
int[] end = new int[N];
end[0] = nums[0];
int index = 0;
for(int i=1; i< N;i++){
if(nums[i] > end[index]){
end[++index] = nums[i];
} else {
for (int j = 0; j <= index; j++) {
if (nums[i] <= end[j]) {
end[j] = nums[i];//替换对应的位置
break;
}
}
}
}
return index + 1;
}
}

View File

@ -0,0 +1,241 @@
package com.markilue.leecode.hot100;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hot100
*@Author: markilue
*@CreateTime: 2023-03-30 10:36
*@Description:
* TODO 力扣301 删除无效的括号:
* 给你一个由若干括号和字母组成的字符串 s 删除最小数量的无效括号使得输入的字符串有效
* 返回所有可能的结果答案可以按 任意顺序 返回
*@Version: 1.0
*/
public class T79_RemoveInvalidParentheses {
//不知道该怎么去重就用set存储结果 18ms
Set<String> set = new HashSet<>();
StringBuilder str;
public List<String> removeInvalidParentheses(String s) {
int lmove = 0;
int rmove = 0;
str = new StringBuilder(s);
//遍历一遍求出要删除左括号和右括号的数量
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
lmove++;
} else if (s.charAt(i) == ')') {
//左右括号可以匹配
if (lmove > 0) {
lmove--;
} else {
rmove++;
}
}
}
dfs(lmove, rmove, 0);
return new ArrayList<>(set);
}
public void dfs(int lmove, int rmove, int i) {
if (lmove == 0 && rmove == 0) {
//判断字符串内括号是否有效
if (isValid(str)) {
set.add(new String(str.toString()));
}
return;
}
//还需要删除的括号个数 小于 能过删除的字符个数
if (lmove + rmove > str.length() - i) {
return;
}
//不删除
dfs(lmove, rmove, i + 1);
//删除分左右括号考虑
if (str.charAt(i) == '(' && lmove > 0) {
str.deleteCharAt(i);//删除
dfs(lmove - 1, rmove, i);//进入下一层因为删除了i处括号所以不需要i+1
str.insert(i, '(');//恢复现场
} else if (str.charAt(i) == ')' && rmove > 0) {
str.deleteCharAt(i);//删除
dfs(lmove, rmove - 1, i);//进入下一层
str.insert(i, ')');//恢复现场
}
}
public boolean isValid(StringBuilder str) {
int left = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '(') {
left++;
} else if (str.charAt(i) == ')') {
left--;
}
if (left < 0) {
return false;
}
}
return true;
}
//自己去重4ms
private List<String> res = new ArrayList<String>();
public List<String> removeInvalidParentheses1(String s) {
int lremove = 0;
int rremove = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
lremove++;
} else if (s.charAt(i) == ')') {
if (lremove == 0) {
rremove++;
} else {
lremove--;
}
}
}
helper(s, 0, lremove, rremove);
return res;
}
private void helper(String str, int start, int lremove, int rremove) {
if (lremove == 0 && rremove == 0) {
if (isValid(str)) {
res.add(str);
}
return;
}
for (int i = start; i < str.length(); i++) {
if (i != start && str.charAt(i) == str.charAt(i - 1)) {
continue;
}
// 如果剩余的字符无法满足去掉的数量要求直接返回
if (lremove + rremove > str.length() - i) {
return;
}
// 尝试去掉一个左括号
if (lremove > 0 && str.charAt(i) == '(') {
helper(str.substring(0, i) + str.substring(i + 1), i, lremove - 1, rremove);
}
// 尝试去掉一个右括号
if (rremove > 0 && str.charAt(i) == ')') {
helper(str.substring(0, i) + str.substring(i + 1), i, lremove, rremove - 1);
}
}
}
private boolean isValid(String str) {
int cnt = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '(') {
cnt++;
} else if (str.charAt(i) == ')') {
cnt--;
if (cnt < 0) {
return false;
}
}
}
return cnt == 0;
}
@Test
public void test(){
String s ="()())()";
System.out.println(removeInvalidParentheses2(s));
}
//自己尝试一遍
public List<String> removeInvalidParentheses2(String s) {
//统计需要去掉的左括号和右括号的数量
int left = 0;
int right = 0;
for (char c : s.toCharArray()) {
if (c == '(') {
left++;
} else if (c == ')') {
if (left == 0) {
right++;
} else {
left--;
}
}
}
helper1(s, left, right, 0);
return res;
}
public void helper1(String s, int left, int right, int start) {
if (left == 0 && right == 0) {
if (isValid1(s)) {
res.add(s);
}
return;
}
for (int i = start; i < s.length(); i++) {
//去重
if (i != start && s.charAt(i) == s.charAt(i - 1)) continue;
if (left + right > s.length() - i) {
//怎么删都不够了
return;
}
//尝试删除左括号
if (left > 0 && s.charAt(i) == '(') {
helper1(s.substring(0, i) + s.substring(i + 1), left - 1, right, i + 1);
}
//尝试删除右括号
if (right > 0 && s.charAt(i) == ')') {
helper1(s.substring(0, i) + s.substring(i + 1), left, right - 1, i + 1);
}
}
}
public boolean isValid1(String s) {
int left = 0;
for (char c : s.toCharArray()) {
if (c == '(') {
left++;
} else if (c == ')') {
if (left == 0) {
return false;
} else {
left--;
}
}
}
return left==0;
}
}

View File

@ -0,0 +1,70 @@
package com.markilue.leecode.hot100;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hot100
*@Author: markilue
*@CreateTime: 2023-03-31 11:13
*@Description: TODO
*@Version: 1.0
*/
public class T80_MaxProfit {
@Test
public void test() {
int[] prices = {1, 2, 3, 0, 2};
System.out.println(maxProfit(prices));
}
/**
* 动态dp,状态分为三种:
* 今天手里没有股票且不在冷冻期dp[i][0]
* 今天手里没有股票且在冷冻期dp[i][1]
* 今天手里有股票dp[i][2]
* @param prices
* @return
*/
public int maxProfit(int[] prices) {
if (prices.length == 1) return 0;
int[][] dp = new int[prices.length][3];
dp[0][0] = 0;
dp[0][1] = 0;
dp[0][2] = -prices[0];
for (int i = 1; i < prices.length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]);//昨天是冷冻期;或者昨天也没买
dp[i][1] = dp[i - 1][2] + prices[i];//必须是今天买入
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][0] - prices[i]);//必须是今天买入
}
return Math.max(dp[dp.length - 1][0], dp[dp.length - 1][1]);
}
//滚动数组优化
public int maxProfit1(int[] prices) {
if (prices.length == 1) return 0;
int dp0 = 0;
int dp1 = 0;
int dp2 = -prices[0];
for (int i = 1; i < prices.length; i++) {
int temp = dp0;
dp0 = Math.max(dp0, dp1);//昨天是冷冻期;或者昨天也没买
dp1 = dp2 + prices[i];//必须是今天买入
dp2 = Math.max(dp2, temp - prices[i]);//必须是今天买入
}
return Math.max(dp0, dp1);
}
}

View File

@ -0,0 +1,120 @@
package com.markilue.leecode.hot100;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.hot100
*@Author: markilue
*@CreateTime: 2023-03-31 11:28
*@Description: TODO
*@Version: 1.0
*/
public class T81_MaxCoins {
@Test
public void test() {
int[] nums = {3, 1, 5, 8};
System.out.println(maxCoins1(nums));
}
/**
* 思路:优先戳中间最小的
* 不对
* @param nums
* @return
*/
public int maxCoins(int[] nums) {
int result = 0;
int count = nums.length;
while (nums[0] != -1) {
int minIndex = 0;
int threshold = nums.length;
if (count == 3) {
boolean flag = false;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == -1) {
threshold = i;
break;
}
if (nums[i] == 1) {
minIndex = i;
flag = true;
}
}
if (!flag) {
minIndex = 1;
}
}else {
for (int i = 1; i < nums.length; i++) {
if (nums[i] == -1) {
threshold = i;
break;
}
if (nums[minIndex] > nums[i]) {
minIndex = i;
}
}
}
//戳i位置
int left;
if (minIndex - 1 < 0) {
left = 1;
} else {
left = nums[minIndex - 1];
}
int right;
if (minIndex + 1 >= threshold) {
right = 1;
} else {
right = nums[minIndex + 1];
}
result += left * nums[minIndex] * right;
System.arraycopy(nums, minIndex + 1, nums, minIndex, threshold - minIndex - 1);
nums[threshold - 1] = -1;
count--;
}
return result;
}
/**
* 官方动态规划法:
* dp[i][j]表示填满开区间(i,j)能得到的最多硬币数
* 最终答案即为 dp[0][n+1]dp[0][n+1]dp[0][n+1]实现时要注意到动态规划的次序
* 动态规划:
* 速度击败27.13% 内存击败45.56% 43ms
* @param nums
* @return
*/
public int maxCoins1(int[] nums) {
int n = nums.length;
int[][] rec = new int[n + 2][n + 2];
int[] val = new int[n + 2];
val[0] = val[n + 1] = 1;
for (int i = 1; i <= n; i++) {
val[i] = nums[i - 1];
}
for (int i = n - 1; i >= 0; i--) {
for (int j = i + 2; j <= n + 1; j++) {
for (int k = i + 1; k < j; k++) {
int sum = val[i] * val[k] * val[j];//计算戳当前点的sum
sum += rec[i][k] + rec[k][j];//计算不要这个点之后的左右点的戳开的和
rec[i][j] = Math.max(rec[i][j], sum);
}
}
}
return rec[0][n + 1];
}
}

View File

@ -15,6 +15,16 @@ import java.util.ArrayList;
*/
public class test {
static {
System.out.println("hello sta");
}
public static void main(String[] args) {
System.out.println("hello world");
}
//测试ArrayList的index是否发生变化
@Test

View File

@ -1,6 +1,7 @@
package com.markilue.leecode.test;
import java.util.HashMap;
import java.util.*;
import java.util.Scanner;
/**
@ -14,53 +15,53 @@ import java.util.Scanner;
public class testAnt {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
new testAnt().test(input);
// StringBuilder output = new StringBuilder();
// int left = 0;
// public static void main(String[] args) {
//
// //去除前面的
// while (left < input.length() && input.charAt(left) == ' ') {
// left++;
// }
// Scanner sc = new Scanner(System.in);
// String input = sc.nextLine();
//
// boolean isCapital = true; // 首字母是否大写
// for (int i = left; i < input.length(); i++) {
// char c = input.charAt(i);
// if (c == ' ') {
// if (i > 0 && input.charAt(i - 1) == '.') {
// output.deleteCharAt(output.length() - 1);
// }
// // 跳过多余的空格
// while (i < input.length() - 1 && input.charAt(i + 1) == ' ') {
// i++;
// }
// if (input.charAt(i + 1) != '.') {
// output.append(' ');
// }
// } else if (c == '.') {
// // 句号后面要加一个空格
// output.append(". ");
// isCapital = true; // 下一句话的首字母要大写
// } else {
// if (isCapital) {
// // 首字母要大写
// output.append(Character.toUpperCase(c));
// isCapital = false;
// } else {
// output.append(c);
// }
// }
// }
// new testAnt().test(input);
//// StringBuilder output = new StringBuilder();
//// int left = 0;
////
//// //去除前面的
//// while (left < input.length() && input.charAt(left) == ' ') {
//// left++;
//// }
////
//// boolean isCapital = true; // 首字母是否大写
//// for (int i = left; i < input.length(); i++) {
//// char c = input.charAt(i);
//// if (c == ' ') {
//// if (i > 0 && input.charAt(i - 1) == '.') {
//// output.deleteCharAt(output.length() - 1);
//// }
//// // 跳过多余的空格
//// while (i < input.length() - 1 && input.charAt(i + 1) == ' ') {
//// i++;
//// }
//// if (input.charAt(i + 1) != '.') {
//// output.append(' ');
//// }
//// } else if (c == '.') {
//// // 句号后面要加一个空格
//// output.append(". ");
//// isCapital = true; // 下一句话的首字母要大写
//// } else {
//// if (isCapital) {
//// // 首字母要大写
//// output.append(Character.toUpperCase(c));
//// isCapital = false;
//// } else {
//// output.append(c);
//// }
//// }
//// }
////
//// System.out.println(output.toString());
// sc.close();
//
// System.out.println(output.toString());
sc.close();
}
// }
public void test(String str) {
@ -106,4 +107,68 @@ public class testAnt {
}
// public static void main(String[] args) {
// Scanner scanner = new Scanner(System.in);
// int k = scanner.nextInt();
// int count = 0;
// for (int i = 0; i < 65536; i++) {
// String hex = String.format("%04x", i); // 将整数转换成长度为 4 的十六进制数
// if (isGoodHex(hex)) {
// count++;
// if (count == k) {
// System.out.println(hex);
// break;
// }
// }
// }
// }
//
// public static boolean isGoodHex(String hex) {
// Set<Character> digits = new HashSet<>();
// for (char c : hex.toCharArray()) {
// digits.add(c);
// }
// return digits.size() == 4;
// }
public static void main(String[] args) {
String s = "????(?"; // 待匹配的字符串
int left = 0, right = 0, count = 0; // 分别记录左括号右括号和合法的括号对的数量
Stack<Integer> stack = new Stack<>(); // 用于记录左括号和 '?' 的下标
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(' || c == '?') {
stack.push(i);
if (c == '(') {
left++;
}
} else {
if (stack.isEmpty()) {
continue;
}
stack.pop();
if (c == ')') {
right++;
}
count++;
}
}
while (!stack.isEmpty()) { // 处理剩余的左括号或 '?'
int index = stack.pop();
if (s.charAt(index) == '(') {
left--;
} else {
right--;
}
}
count += Math.min(left, right); // '?' 可以代替左括号或右括号因此左右括号数量较小的值为合法的括号对数量
System.out.println(count);
}
}