leecode更新

This commit is contained in:
markilue 2023-02-19 15:23:27 +08:00
parent bc3caaf14e
commit 9439d99bb6
3 changed files with 254 additions and 0 deletions

View File

@ -0,0 +1,38 @@
package com.markilue.leecode.dynamic.second;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-19 13:41
*@Description:
* TODO 力扣70 爬楼梯(进阶版):
* 假设你正在爬楼梯需要 n 阶你才能到达楼顶
* 每次你可以爬 1 2 个台阶你有多少种不同的方法可以爬到楼顶呢
*@Version: 1.0
*/
public class T14_ClimbStairs {
/**
* 思路:可以看做是一个完全背包问题: 背包大小是n,nums为[1,2];
* 由于爬楼梯先爬1后爬2和先爬2后爬1是不一样的结果所以遍历nums需要放里面
* 速度击败100% 内存击败27.4%
* @param n
* @return
*/
public int climbStairs(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
for (int j = 0; j < dp.length; j++) {
for (int i = 1; i <= 2; i++) {//可以走1或者2
if (j >= i) dp[j] = dp[j - i] + dp[j];
}
}
return dp[n];
}
}

View File

@ -0,0 +1,116 @@
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-19 13:58
*@Description:
* TODO 力扣322题 零钱兑换:
* 给你一个整数数组 coins 表示不同面额的硬币以及一个整数 amount 表示总金额
* 计算并返回可以凑成总金额所需的 最少的硬币个数 如果没有任何一种硬币组合能组成总金额返回 -1
* 你可以认为每种硬币的数量是无限的
*@Version: 1.0
*/
public class T15_CoinChange {
@Test
public void test() {
int[] coins = {1, 2, 5};
int amount = 11;
System.out.println(coinChange(coins, amount));
}
@Test
public void test1() {
int[] coins = {2};
int amount = 3;
System.out.println(coinChange1(coins, amount));
}
@Test
public void test2() {
int[] coins = {2, 5, 10, 1};
int amount = 27;
System.out.println(coinChange(coins, amount));
}
@Test
public void test3() {
int[] coins = {186,419,83,408};
int amount = 6249;
System.out.println(coinChange(coins, amount));
}
/**
* 思路:从一共有多少种方法解决变成了这些方法中最少可以用多少种:
* TODO dp五部曲:
* 1.dp定义: dp[i][j]表示使用nums[0-i]凑出j的使用最少货币数
* 2.dp状态转移方程: dp[i][j]可以选择 再多使用当前nums[i]一次 或者 不适用当前nums[i]
* dp[i][j]=min(dp[i][j-nums[i]]+1,dp[i-1][j])
* 3.dp初始化:dp[i][0]=0
* 4.dp遍历顺序:求的组合数所以nums在外
* 5.dp举例推导:coins = [1, 2, 5], amount = 11
* [0 1 2 3 4 5 6 7 8 9 10 11]
* i=1: 0 1 2 3 4 5 6 7 8 9 10 11
* i=2: 0 1 1 2 2 3 3 4 4 5 5 6
* i=5: 0 1 1 2 2 1 2 2 3 3 2 3
* 速度击败23.5%
* @param coins
* @param amount
* @return
*/
public int coinChange(int[] coins, int amount) {
int[][] dp = new int[coins.length][amount + 1];
Arrays.sort(coins);
for (int[] d : dp) {
Arrays.fill(d, Integer.MAX_VALUE); //注意这里必须是Max_Value不能是Min_Value,否则Min可能取不到
}
dp[0][0] = 0;
for (int i = 1; i < dp[0].length; i++) {
if (i >= coins[0] && dp[0][i - coins[0]] != Integer.MAX_VALUE) dp[0][i] = dp[0][i - coins[0]] + 1;
}
for (int i = 1; i < coins.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
if (j >= coins[i] && dp[i][j - coins[i]] != Integer.MAX_VALUE)
dp[i][j] = Math.min(dp[i][j - coins[i]] + 1, dp[i - 1][j]);
else dp[i][j] = dp[i - 1][j];
}
}
return dp[coins.length - 1][amount] == Integer.MAX_VALUE ? -1 : dp[coins.length - 1][amount];
}
/**
* 一维dp优化
* @param coins
* @param amount
* @return
*/
public int coinChange1(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp,Integer.MAX_VALUE);
dp[0]=0;
for (int i = 0; i < coins.length; i++) {
for (int j = coins[i]; j < dp.length; j++) {
if (dp[j-coins[i]]!=Integer.MAX_VALUE)
dp[j] = Math.min(dp[j - coins[i]] + 1, dp[j]);
}
}
return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
}
}

View File

@ -0,0 +1,100 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-19 14:55
*@Description:
* TODO 力扣279 完全平方数:
* 给你一个整数 n 返回 和为 n 的完全平方数的最少数量
* 完全平方数 是一个整数其值等于另一个整数的平方换句话说其值等于一个整数自乘的积例如149 16 都是完全平方数 3 11 不是
*@Version: 1.0
*/
public class T16_NumSquares {
@Test
public void test() {
// int t = 10;
// System.out.println(Math.sqrt(t));
// System.out.println((int) Math.sqrt(t));
// System.out.println((int) Math.sqrt(9) == Math.sqrt(9));
System.out.println(numSquares(12));
}
/**
* 思路:与上一个零钱问题类似事实上零钱问题给出了可用的零钱数;而这一题需要判断是否是可用的零钱,
* TODO dp五部曲:
* 1.dp定义:dp[j]表示使用完全平方数能凑出的最少个数
* 2.dp状态转移方程:dp[j]=min(dp[j],dp[j-完全])
* 3.dp初始化:dp[0]=0;
* 4.dp遍历顺序:都可以
* 5.dp状态转移方程: n=12:
* [0 1 2 3 4 5 6 7 8 9 10 11 12]
* i=1: 0 1 2 3 4 5 6 7 8 9 10 11 12
* i=4: 0 1 2 3 1 2 3 4 2 3 4 5 3
* i=9: 0 1 2 3 1 2 3 4 2 1 2 3 3
* 速度击败9.4% 内存击败37.54% 157ms
* @param n
* @return
*/
public int numSquares(int n) {
List<Integer> list = findSquares(n);
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 0; i < list.size(); i++) {
for (int j = list.get(i); j < dp.length; j++) {
if (dp[j - list.get(i)] != Integer.MAX_VALUE) dp[j] = Math.min(dp[j], dp[j - list.get(i)] + 1);
}
}
return dp[n];
}
public List<Integer> findSquares(int n) {
List<Integer> list = new ArrayList<>();
for (int i = 1; i <= n; i++) {
if ((int) Math.sqrt(i) == Math.sqrt(i)) {
list.add(i);
}
}
return list;
}
/**
* 官方一维dp,避免判断完全平方数
* 速度击败65.5% 内存击败44.71%
* @param n
* @return
*/
public int numSquares1(int n) {
int max = n + 1; //因为最少可以用1凑n,最多只需要n个数字
int[] dp = new int[n + 1];
dp[0] = 0;
for (int i = 1; i < max; i++) {
dp[i] = max;
}
int maxSqrt = (int) Math.sqrt(n);
for (int i = 1; i <= maxSqrt; i++) {
for (int j = i * i; j < n + 1; j++) {
if (dp[j - i * i] != max) {
dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
}
}
}
return dp[n];
}
}