From 7b5c5e4c08fde949af8ae3cad98f1cc275e70ed0 Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Tue, 15 Apr 2025 11:44:47 +0800 Subject: [PATCH] =?UTF-8?q?4.15=20=E5=8A=A8=E8=A7=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/dynamic_programming/CoinChange.java | 38 +++++++++++++++++ .../java/dynamic_programming/NumSquares.java | 33 +++++++++++++++ src/main/java/dynamic_programming/Rob.java | 41 +++++++++++++++++++ src/main/java/dynamic_programming/Rob2.java | 37 +++++++++++++++++ .../java/dynamic_programming/WordBreak.java | 31 ++++++++++++++ .../dynamic_programming/CoinChangeTest.java | 17 ++++++++ .../dynamic_programming/WordBreakTest.java | 21 ++++++++++ 7 files changed, 218 insertions(+) create mode 100644 src/main/java/dynamic_programming/CoinChange.java create mode 100644 src/main/java/dynamic_programming/NumSquares.java create mode 100644 src/main/java/dynamic_programming/Rob.java create mode 100644 src/main/java/dynamic_programming/Rob2.java create mode 100644 src/main/java/dynamic_programming/WordBreak.java create mode 100644 src/test/java/dynamic_programming/CoinChangeTest.java create mode 100644 src/test/java/dynamic_programming/WordBreakTest.java diff --git a/src/main/java/dynamic_programming/CoinChange.java b/src/main/java/dynamic_programming/CoinChange.java new file mode 100644 index 0000000..57f695c --- /dev/null +++ b/src/main/java/dynamic_programming/CoinChange.java @@ -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]; + } +} diff --git a/src/main/java/dynamic_programming/NumSquares.java b/src/main/java/dynamic_programming/NumSquares.java new file mode 100644 index 0000000..2f87aec --- /dev/null +++ b/src/main/java/dynamic_programming/NumSquares.java @@ -0,0 +1,33 @@ +package dynamic_programming; + +import java.util.Arrays; + +/** + * 题目: 279. 完全平方数 (numSquares) + * 描述:给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。 + * 完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 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]; + } +} diff --git a/src/main/java/dynamic_programming/Rob.java b/src/main/java/dynamic_programming/Rob.java new file mode 100644 index 0000000..9ad7100 --- /dev/null +++ b/src/main/java/dynamic_programming/Rob.java @@ -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]; + } +} diff --git a/src/main/java/dynamic_programming/Rob2.java b/src/main/java/dynamic_programming/Rob2.java new file mode 100644 index 0000000..8fadca4 --- /dev/null +++ b/src/main/java/dynamic_programming/Rob2.java @@ -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; + } +} diff --git a/src/main/java/dynamic_programming/WordBreak.java b/src/main/java/dynamic_programming/WordBreak.java new file mode 100644 index 0000000..2edb542 --- /dev/null +++ b/src/main/java/dynamic_programming/WordBreak.java @@ -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 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]; + } +} diff --git a/src/test/java/dynamic_programming/CoinChangeTest.java b/src/test/java/dynamic_programming/CoinChangeTest.java new file mode 100644 index 0000000..329dcb5 --- /dev/null +++ b/src/test/java/dynamic_programming/CoinChangeTest.java @@ -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); + } +} \ No newline at end of file diff --git a/src/test/java/dynamic_programming/WordBreakTest.java b/src/test/java/dynamic_programming/WordBreakTest.java new file mode 100644 index 0000000..ec1627d --- /dev/null +++ b/src/test/java/dynamic_programming/WordBreakTest.java @@ -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 wordDict =new ArrayList<>(){}; + wordDict.add("apple"); + wordDict.add("pen"); + wordBreak.wordBreak(s,wordDict); + } +} \ No newline at end of file