leecode更新

This commit is contained in:
markilue 2023-02-16 14:22:22 +08:00
parent 4d3148c403
commit f7ccdf71e5
4 changed files with 431 additions and 1 deletions

View File

@ -1,5 +1,7 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
@ -16,6 +18,14 @@ package com.markilue.leecode.dynamic.second;
*/
public class T09_LastStoneWeightII {
@Test
public void test() {
String str1 = new String("1") + new String("1");
str1.intern();
String str2 = "11";
System.out.println(str1 == str2);
}
/**
* 思路:消石头可以理解为总有一些是用来消另一些的那么可以变为让一堆+去消另一堆-

View File

@ -0,0 +1,124 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-16 10:20
*@Description:
* TODO 力扣394题 目标和:
* 给你一个整数数组 nums 和一个整数 target
* 向数组中的每个整数前添加 '+' '-' 然后串联起所有整数可以构造一个 表达式
* 例如nums = [2, 1] 可以在 2 之前添加 '+' 1 之前添加 '-' 然后串联起来得到表达式 "+2-1"
* 返回可以通过上述方法构造的运算结果等于 target 的不同 表达式 的数目
* 1 <= nums.length <= 20
* 0 <= nums[i] <= 1000
* 0 <= sum(nums[i]) <= 1000
* -1000 <= target <= 1000
*@Version: 1.0
*/
public class T10_FindTargetSumWays {
@Test
public void test() {
int[] nums = {100};
int target = -200;
System.out.println(findTargetSumWays(nums, target));
}
/**
* 思路:可以计算出sum出来然后有正的一半有负的一半那么x-(sum-x)=target;x=(sum+target)/2;所以又转为了背包问题
* TODO DP五部曲:
* 1.dp定义:dp[i][j]表示使用nums[0-i]能凑出j的方法数
* 2.dp状态转移方程:
* 1.dp[i][j]有两种方式得到
* 1)使用当前的数nums[i]: dp[i-1][j-nums[i]]
* 2)不使用当前的数nums[i]: dp[i-1][j]
* dp[i][j]=dp[i-1][j-nums[i]]+dp[i-1][j]
* 3.dp初始化:dp[i][0]=1 dp[0][j==nums[0]]=1
* 4.dp遍历顺序:从上到下 从前往后
* 5.dp举例推导:
* 速度击败67.3% 内存击败12%
* @param nums
* @param target
* @return
*/
public int findTargetSumWays(int[] nums, int target) {
// if (nums.length == 1) {
// return nums[0] == target ? 1 : 0;
// }
int sum = 0;
for (int num : nums) {
sum += num;
}
if ((sum + target) % 2 != 0) return 0;
if ((sum + target) < 0) return 0;//注意条件-1000 <= target <= 1000
int need = (sum + target) / 2;
int[][] dp = new int[nums.length][need + 1];
//初始化
for (int i = 0; i < dp.length; i++) {
dp[i][0] = 1;
}
for (int i = 0; i < dp[0].length; i++) {
if (i == nums[0]) {
dp[0][i] += 1;
break;
}
}
for (int i = 1; i < dp.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
if (j >= nums[i]) dp[i][j] = dp[i - 1][j - nums[i]] + dp[i - 1][j];
else dp[i][j] = dp[i - 1][j];
}
}
return dp[dp.length - 1][need];
}
/**
* 一维dp优化
* 速度击败94.6% 内存击败42.53% 2ms
* @param nums
* @param target
* @return
*/
public int findTargetSumWays1(int[] nums, int target) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if ((sum + target) % 2 != 0) return 0;
if ((sum + target) < 0) return 0;//注意条件-1000 <= target <= 1000
int need = (sum + target) / 2;
int[] dp = new int[need + 1];
//初始化
dp[0] = 1;
for (int i = 0; i < dp.length; i++) {
if (i == nums[0]) {
dp[i] += 1;
break;
}
}
for (int i = 1; i < nums.length; i++) {
for (int j = dp.length - 1; j >= nums[i]; j--) {
dp[j] = dp[j - nums[i]] + dp[j];
}
}
return dp[need];
}
}

View File

@ -0,0 +1,209 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
import java.util.Arrays;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-16 10:58
*@Description:
* TODO 力扣474题 一和零:
* 给你一个二进制字符串数组 strs 和两个整数 m n
* 请你找出并返回 strs 的最大子集的长度该子集中 最多 m 0 n 1
* 如果 x 的所有元素也是 y 的元素集合 x 是集合 y 子集
*@Version: 1.0
*/
public class T11_FindMaxForm {
@Test
public void test() {
String[] strs = {"10", "0", "1"};
int m = 1, n = 1;
System.out.println(findMaxForm(strs, m, n));
}
/**
* 思路:可以看做是有两个限制的背包:
* TODO DP五部曲:
* 1.dp定义:dp[i][j][k]表示使用strs[0-i]而背包大小为j和k时最多的数量
* 2.dp状态转移方程:
* 1.dp[i][j][k]可以使用str[i]或者不适用str[i]
* dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-str[i 0]][k-str[i `0`]]+1)
* 3.dp初始化:dp[i][0][k]=0;dp[i][j][0]=0;dp[0][j][k]=1;
* 4.dp遍历顺序:
* 速度击败6.33% 内存击败5.2% 64ms
* @param strs
* @param m
* @param n
* @return
*/
public int findMaxForm(String[] strs, int m, int n) {
//记录每个zero,one个数
int[][] nums = new int[strs.length][2];
int count = -1;
for (String str : strs) {
int zero = 0;
int one = 0;
for (char c : str.toCharArray()) {
if (c == '0') zero++;
else one++;
}
nums[++count] = new int[]{zero, one};
}
//初始化
int[][][] dp = new int[strs.length][m + 1][n + 1];
for (int i = nums[0][0]; i < m + 1; i++) {
for (int j = nums[0][1]; j < n + 1; j++) {
dp[0][i][j] = 1;
}
}
for (int i = 1; i < dp.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
if (j < nums[i][0]) dp[i][j] = dp[i - 1][j];
else {
for (int k = 0; k < dp[0][0].length; k++) {
if (k < nums[i][1]) dp[i][j][k] = dp[i - 1][j][k];
else dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j - nums[i][0]][k - nums[i][1]] + 1);
}
}
}
}
return dp[dp.length - 1][m][n];
}
/**
* 二维dp优化
* 速度击败30.23% 内存击败98.69% 27ms
* @param strs
* @param m
* @param n
* @return
*/
public int findMaxForm1(String[] strs, int m, int n) {
//记录每个zero,one个数
int[][] nums = new int[strs.length][2];
int count = -1;
for (String str : strs) {
int zero = 0;
int one = 0;
for (char c : str.toCharArray()) {
if (c == '0') zero++;
else one++;
}
nums[++count] = new int[]{zero, one};
}
//初始化
int[][] dp = new int[m + 1][n + 1];
for (int i = nums[0][0]; i < m + 1; i++) {
for (int j = nums[0][1]; j < n + 1; j++) {
dp[i][j] = 1;
}
}
for (int i = 1; i < strs.length; i++) {
for (int j = dp.length - 1; j >= nums[i][0]; j--) {
for (int k = dp[0].length - 1; k >= nums[i][1]; k--) {
dp[j][k] = Math.max(dp[j][k], dp[j - nums[i][0]][k - nums[i][1]] + 1);
}
}
}
return dp[m][n];
}
/**
* 进一步优化少for循环求nums一次
* 速度击败97.12% 内存击败49.46% 16ms
* @param strs
* @param m
* @param n
* @return
*/
public int findMaxForm2(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
int length = strs.length;
for (int i = 0; i < length; i++) {
int[] zerosOnes = getZerosOnes(strs[i]);
int zeros = zerosOnes[0], ones = zerosOnes[1];
for (int j = m; j >= zeros; j--) {
for (int k = n; k >= ones; k--) {
dp[j][k] = Math.max(dp[j][k], dp[j - zeros][k - ones] + 1);
}
}
}
return dp[m][n];
}
public int[] getZerosOnes(String str) {
int[] zerosOnes = new int[2];
int length = str.length();
for (int i = 0; i < length; i++) {
zerosOnes[str.charAt(i) - '0']++;
}
return zerosOnes;
}
/**
* 官方最快:回溯
* 速度击败100% 内存击败99.84% 6ms
*/
int max = 0;
public int findMaxForm3(String[] strs, int m, int n) {
int len = strs.length;
int[][] counts = new int[len][2];
for(int i = 0; i < len; i++) {
counts[i] = count(strs[i]);
}
Arrays.sort(counts, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
backTrace(counts, 0, m, n, 0);
return max;
}
private void backTrace(int[][] counts, int index, int m, int n, int currLength) {
if(m < 0 || n < 0) return;
for(int i = index; i < counts.length; i++) {
int[] count = counts[i];
if(i > index && count[0] == counts[i-1][0]) continue;
if(count[0] <= m && count[1] <= n) {
max = Math.max(max, currLength + 1);
backTrace(counts, i + 1, m - count[0], n - count[1], currLength + 1);
}
}
}
private int[] count(String s) {
int oneCount = 0;
int zeroCount = 0;
int i = s.length() - 1;
while(i >= 0) {
char sc = s.charAt(i);
if(sc == '1') {
oneCount++;
}
else {
zeroCount++;
}
i--;
}
return new int[]{zeroCount,oneCount};
}
}

View File

@ -0,0 +1,87 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-16 11:54
*@Description:
* TODO 力扣518题 零钱兑换II:
* 给你一个整数数组 coins 表示不同面额的硬币另给一个整数 amount 表示总金额
* 请你计算并返回可以凑成总金额的硬币组合数如果任何硬币组合都无法凑出总金额返回 0
* 假设每一种面额的硬币有无限个
* 题目数据保证结果符合 32 位带符号整数
*@Version: 1.0
*/
public class T12_Change {
@Test
public void test() {
int amount = 500;
int[] coins = {2, 7, 13};
System.out.println(change(amount, coins));
}
/**
* 思路:完全背包问题 -> 可以重复使用coins
* TODO DP五部曲:
* 1.dp含义:dp[i][j]表示使用coins[0-i]能凑出coins的方式
* 2.dp状态转移方程:dp[i][j]有两种方式凑出 : 使用coins[i] 不使用coins[i]
* dp[i][j]=dp[i-1][j]+dp[i][j-coins[i]]
* 3.dp初始化:dp[i][0]=1 dp[0][j%coins[0]==0]=1
* 4.dp遍历顺序:先遍历coins再遍历背包因为求的是组合数
* 5.dp举例推导:
* 速度击败26.38% 内存击败19.51%
* @param amount
* @param coins
* @return
*/
public int change(int amount, int[] coins) {
int[][] dp = new int[coins.length][amount + 1];
for (int i = 0; i < dp.length; i++) {
dp[i][0] = 1;
}
for (int i = 1; i < dp[0].length; i++) {
if (i % coins[0] == 0) dp[0][i] = 1;
}
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp[0].length; j++) {
if (j < coins[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i]];
}
}
return dp[coins.length - 1][amount];
}
/**
* 一维dp优化
* 速度击败41.89% 内存击败54.24%
* @param amount
* @param coins
* @return
*/
public int change1(int amount, int[] coins) {
int[] dp = new int[amount + 1];
for (int i = 0; i < dp.length; i++) {
if (i % coins[0] == 0) dp[i] = 1;
}
for (int i = 1; i < coins.length; i++) {
for (int j = 1; j < dp.length; j++) {
if (j - coins[i] >= 0) dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
}