From c0a6bc5455921be9b4d1576deedbfecb2cead6e8 Mon Sep 17 00:00:00 2001 From: 5renyuebing Date: Tue, 5 Mar 2019 11:21:35 +0800 Subject: [PATCH] =?UTF-8?q?=E8=83=8C=E5=8C=85=E9=97=AE=E9=A2=98=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/notes/Leetcode 题解.md | 117 ++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 44 deletions(-) diff --git a/docs/notes/Leetcode 题解.md b/docs/notes/Leetcode 题解.md index 9310948f..e09e25d2 100644 --- a/docs/notes/Leetcode 题解.md +++ b/docs/notes/Leetcode 题解.md @@ -3140,37 +3140,6 @@ private int findTargetSumWays(int[] nums, int start, int S) { } ``` -**字符串按单词列表分割** - -[139. Word Break (Medium)](https://leetcode.com/problems/word-break/description/) - -```html -s = "leetcode", -dict = ["leet", "code"]. -Return true because "leetcode" can be segmented as "leet code". -``` - -dict 中的单词没有使用次数的限制,因此这是一个完全背包问题。 - -0-1 背包和完全背包在实现上的不同之处是,0-1 背包对物品的迭代是在最外层,而完全背包对物品的迭代是在最里层。 - -```java -public boolean wordBreak(String s, List wordDict) { - int n = s.length(); - boolean[] dp = new boolean[n + 1]; - dp[0] = true; - for (int i = 1; i <= n; i++) { - for (String word : wordDict) { // 完全一个物品可以使用多次 - int len = word.length(); - if (len <= i && word.equals(s.substring(i - len, i))) { - dp[i] = dp[i] || dp[i - len]; - } - } - } - return dp[n]; -} -``` - **01 字符构成最多的字符串** [474. Ones and Zeroes (Medium)](https://leetcode.com/problems/ones-and-zeroes/description/) @@ -3229,23 +3198,83 @@ return -1. - 物品大小:面额 - 物品价值:数量 -因为硬币可以重复使用,因此这是一个完全背包问题。 +因为硬币可以重复使用,因此这是一个完全背包问题。完全背包只需要将01背包中逆序遍历bp数组改为正序遍历即可。 ```java public int coinChange(int[] coins, int amount) { - if (coins == null || coins.length == 0) { - return 0; - } - int[] minimum = new int[amount + 1]; - Arrays.fill(minimum, amount + 1); - minimum[0] = 0; - Arrays.sort(coins); - for (int i = 1; i <= amount; i++) { - for (int j = 0; j < coins.length && coins[j] <= i; j++) { - minimum[i] = Math.min(minimum[i], minimum[i - coins[j]] + 1); + if(amount == 0) return 0; + int[] bp = new int[amount + 1]; + for(int coin : coins){ + for(int i = coin; i <= amount; i++){ //将逆序遍历改为正序遍历 + if(i == coin) + bp[i] = 1; + else if(bp[i] == 0 && bp[i - coin] != 0) + bp[i] = bp[i - coin] + 1; + else if(bp[i - coin] != 0) + bp[i] = Math.min(bp[i], bp[i - coin] + 1); } } - return minimum[amount] > amount ? -1 : minimum[amount]; + return bp[amount] == 0 ? -1 : bp[amount]; +} +``` + +**找零钱的硬币数组合** + +[518. Coin Change 2 (Medium)](https://leetcode.com/problems/coin-change-2/description/) + +```html +Input: amount = 5, coins = [1, 2, 5] +Output: 4 +Explanation: there are four ways to make up the amount: +5=5 +5=2+2+1 +5=2+1+1+1 +5=1+1+1+1+1 +``` + +完全背包问题,使用dp记录可达成目标的组合数目。 + +```java +public int change(int amount, int[] coins) { + int[] dp = new int[amount + 1]; + dp[0] = 1; + for(int coin : coins){ + for(int i = coin; i <= amount; i++){ + dp[i] += dp[i - coin]; + } + } + return dp[amount]; +} +``` + +**字符串按单词列表分割** + +[139. Word Break (Medium)](https://leetcode.com/problems/word-break/description/) + +```html +s = "leetcode", +dict = ["leet", "code"]. +Return true because "leetcode" can be segmented as "leet code". +``` + +dict 中的单词没有使用次数的限制,因此这是一个完全背包问题。该问题涉及到字典中单词的使用顺序,因此可理解为涉及顺序的完全背包问题。 + +求解该类型问题时,应调整两次循环的顺序,0-1 背包对物品的迭代是在最外层,而涉及顺序的完全背包问题对物品的迭代是在最里层。 + +```java +public boolean wordBreak(String s, List wordDict) { + int n = s.length(); + boolean[] dp = new boolean[n + 1]; + dp[0] = true; + for (int i = 1; i <= n; i++) { + for (String word : wordDict) { // 完全一个物品可以使用多次 + int len = word.length(); + if (len <= i && word.equals(s.substring(i - len, i))) { + dp[i] = dp[i] || dp[i - len]; + } + } + } + return dp[n]; } ``` @@ -3271,7 +3300,7 @@ Note that different sequences are counted as different combinations. Therefore the output is 7. ``` -完全背包。 +涉及顺序的完全背包。 ```java public int combinationSum4(int[] nums, int target) {