4.15 动规

This commit is contained in:
zhangsan 2025-04-15 11:44:47 +08:00
parent 4ea0dcfb2d
commit 7b5c5e4c08
7 changed files with 218 additions and 0 deletions

View File

@ -0,0 +1,38 @@
package dynamic_programming;
import java.util.Arrays;
/**
* 题目 322. 零钱兑换 (coinChange )
* 描述给你一个整数数组 coins 表示不同面额的硬币以及一个整数 amount 表示总金额
* 计算并返回可以凑成总金额所需的 最少的硬币个数 如果没有任何一种硬币组合能组成总金额返回 -1
* 你可以认为每种硬币的数量是无限的
示例 2
输入coins = [1, 2, 5], amount = 11
输出3
解释11 = 5 + 5 + 1
* 链接https://leetcode.cn/problems/coin-change/
*/
public class CoinChange {
public int coinChange(int[] coins, int amount) {
int max = amount+1;
int[] dp = new int[amount + 1];
//初始化dp数组为最大值
Arrays.fill(dp,max);
//当金额为0时需要的硬币数目为0
dp[0] = 0;
for (int i = 0; i < coins.length; i++) {
//正序遍历完全背包每个硬币可以选择多次
for (int j = coins[i]; j <= amount; j++) {
//只有dp[j-coins[i]]不是初始最大值时该位才有选择的必要
if (dp[j - coins[i]] != max) {
//选择硬币数目最小的情况
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
}
}
}
return dp[amount] == max ? -1 : dp[amount];
}
}

View File

@ -0,0 +1,33 @@
package dynamic_programming;
import java.util.Arrays;
/**
* 题目 279. 完全平方数 (numSquares)
* 描述给你一个整数 n 返回 和为 n 的完全平方数的最少数量
* 完全平方数 是一个整数其值等于另一个整数的平方换句话说其值等于一个整数自乘的积例如149 16 都是完全平方数 3 11 不是
示例 2
输入n = 12
输出3
解释12 = 4 + 4 + 4
* 链接https://leetcode.cn/problems/perfect-squares/
*/
public class NumSquares {
public int numSquares(int n) {
int[]dp=new int[n+1];
double sqrted=Math.sqrt(n);
int soft_max=(int) sqrted;
Arrays.fill(dp,n+1);
dp[0]=0;
for (int i = 1; i <= soft_max; i++) {
for (int j = 1; j <= n; j++) {
int cur= (int) Math.pow(i,2);
if(j>=cur &&dp[j-cur]!=n+1)
dp[j]=Math.min(dp[j],dp[(int) (j-Math.pow(i,2))]+1);
}
}
return dp[n];
}
}

View File

@ -0,0 +1,41 @@
package dynamic_programming;
/**
* 题目 198. 打家劫舍 (rob)
* 描述你是一个专业的小偷计划偷窃沿街的房屋每间房内都藏有一定的现金影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统如果两间相邻的房屋在同一晚上被小偷闯入系统会自动报警
* 给定一个代表每个房屋存放金额的非负整数数组计算你 不触动警报装置的情况下 一夜之内能够偷窃到的最高金额
*
示例 2
输入[1,2,3,1]
输出4
解释偷窃 1 号房屋 (金额 = 1) 然后偷窃 3 号房屋 (金额 = 3)
偷窃到的最高金额 = 1 + 3 = 4
* 链接https://leetcode.cn/problems/house-robber/
*/
public class Rob {
public int rob1(int[] nums) {
int cnt=nums.length;
int[][]dp=new int[cnt][2];
dp[0][0]=0;
dp[0][1]=nums[0];
for (int i = 1; i < cnt; i++) {
dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]);
dp[i][1]=dp[i-1][0]+nums[i];
}
return Math.max(dp[cnt-1][0],dp[cnt-1][1]);
}
//推荐这 一维dp
public int rob(int[] nums) {
if (nums == null || nums.length == 0) return 0;
if (nums.length == 1) return nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(dp[0], nums[1]);
for (int i = 2; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[nums.length - 1];
}
}

View File

@ -0,0 +1,37 @@
package dynamic_programming;
/**
* 题目 213. 打家劫舍 II (rob)
* 描述你是一个专业的小偷计划偷窃沿街的房屋每间房内都藏有一定的现金这个地方所有的房屋都 围成一圈 这意味着第一个房屋和最后一个房屋是紧挨着的同时相邻的房屋装有相互连通的防盗系统如果两间相邻的房屋在同一晚上被小偷闯入系统会自动报警
* 给定一个代表每个房屋存放金额的非负整数数组计算你 在不触动警报装置的情况下 今晚能够偷窃到的最高金额
*
示例 2
输入nums = [2,3,2]
输出3
解释你不能先偷窃 1 号房屋金额 = 2然后偷窃 3 号房屋金额 = 2, 因为他们是相邻的
* 链接https://leetcode.cn/problems/house-robber-ii/
*/
public class Rob2 {
public int rob(int[] nums) {
int n = nums.length;
if (n == 0) return 0;
if (n == 1) return nums[0];
// 情况一不抢第一家 [1..n-1]
int max1 = robLinear(nums, 1, n - 1);
// 情况二不抢最后一家 [0..n-2]
int max2 = robLinear(nums, 0, n - 2);
return Math.max(max1, max2);
}
// 经典线性打家劫舍区间 [start..end]
private int robLinear(int[] nums, int start, int end) {
int prev2 = 0; // dp[i-2]
int prev1 = 0; // dp[i-1]
for (int i = start; i <= end; i++) {
int curr = Math.max(prev1, prev2 + nums[i]);
prev2 = prev1;
prev1 = curr;
}
return prev1;
}
}

View File

@ -0,0 +1,31 @@
package dynamic_programming;
import java.util.List;
/**
* 题目 139. 单词拆分 (wordBreak)
* 描述给你一个字符串 s 和一个字符串列表 wordDict 作为字典如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true
* 注意不要求字典中出现的单词全部都使用并且字典中的单词可以重复使用
示例 2
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" "code" 拼接成
* 链接https://leetcode.cn/problems/word-break/
*/
public class WordBreak {
public boolean wordBreak(String s, List<String> wordDict) {
int total=s.length();
boolean[] dp=new boolean[total+1];
dp[0]=true;
for (int j = 1; j <= total; j++) {
for (String cur : wordDict) {
int cnt = cur.length();
if (j >= cnt)
dp[j] = dp[j] || (dp[j - cnt] && s.substring(j - cnt, j).equals(cur));
}
}
return dp[total];
}
}

View File

@ -0,0 +1,17 @@
package dynamic_programming;
import org.junit.Test;
import static org.junit.Assert.*;
public class CoinChangeTest {
@Test
public void coinChange() {
CoinChange coinChange = new CoinChange();
int[]coins = {2};
int amount = 1;
int res=coinChange.coinChange(coins,amount);
System.out.println(res);
}
}

View File

@ -0,0 +1,21 @@
package dynamic_programming;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
public class WordBreakTest {
@Test
public void wordBreak() {
WordBreak wordBreak = new WordBreak();
String s = "applepenapple";
List<String> wordDict =new ArrayList<>(){};
wordDict.add("apple");
wordDict.add("pen");
wordBreak.wordBreak(s,wordDict);
}
}