赞
踩
讲解链接:代码随想录-139.单词拆分
确定 dp 数组以及下标的含义:dp[i] : 字符串长度为 i 的话,dp[i]为 true,表示可以拆分为一个或多个在字典中出现的单词。
确定递推公式:如果确定 dp[j] 是 true,且 [j, i] 这个区间的子串出现在字典里,那么 dp[i]一定是 true。(j < i )。
所以递推公式是 if([j, i] 这个区间的子串出现在字典里 && dp[j]是 true) 那么 dp[i] = true。
dp 数组如何初始化:从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为 true,那么 dp[0]就是递推的根基,dp[0]一定要为 true,否则递推下去后面都都是 false 了。
确定遍历顺序:题目中说是拆分为一个或多个在字典中出现的单词,所以这是完全背包。还要讨论两层 for 循环的前后顺序。
- public boolean wordBreak(String s, List<String> wordDict) {
- boolean[] dp = new boolean[s.length() + 1];
- dp[0] = true;
-
- for (int i = 1; i < dp.length; i++) {
- for (int j = 0; j < wordDict.size(); j++) {
- String str = wordDict.get(j);
- Integer len = str.length();
- if (i >= len && dp[i - len] && str.equals(s.substring(i - len, i))) {
- dp[i] = true;
- break;
- }
- }
- }
-
- return dp[dp.length - 1];
- }
讲解链接:代码随想录-关于多重背包,你该了解这些!
版本二:改变遍历个数
- public void testMultiPack2() {
- // 版本二:改变遍历个数
- int[] weight = new int[]{1, 3, 4};
- int[] value = new int[]{15, 20, 30};
- int[] nums = new int[]{2, 3, 2};
- int bagWeight = 10;
-
- int[] dp = new int[bagWeight + 1];
- for (int i = 0; i < weight.length; i++) { // 遍历物品
- for (int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
- // 以上为01背包,然后加一个遍历个数
- for (int k = 1; k <= nums[i] && (j - k * weight[i]) >= 0; k++) { // 遍历个数
- dp[j] = Math.max(dp[j], dp[j - k * weight[i]] + k * value[i]);
- }
- System.out.println(Arrays.toString(dp));
- }
- }
- }
版本一:改变物品数量为 01 背包格式
- public void testMultiPack1() {
- // 版本一:改变物品数量为01背包格式
- List<Integer> weight = new ArrayList<>(Arrays.asList(1, 3, 4));
- List<Integer> value = new ArrayList<>(Arrays.asList(15, 20, 30));
- List<Integer> nums = new ArrayList<>(Arrays.asList(2, 3, 2));
- int bagWeight = 10;
-
- for (int i = 0; i < nums.size(); i++) {
- while (nums.get(i) > 1) { // 把物品展开为i
- weight.add(weight.get(i));
- value.add(value.get(i));
- nums.set(i, nums.get(i) - 1);
- }
- }
-
- int[] dp = new int[bagWeight + 1];
- for (int i = 0; i < weight.size(); i++) { // 遍历物品
- for (int j = bagWeight; j >= weight.get(i); j--) { // 遍历背包容量
- dp[j] = Math.max(dp[j], dp[j - weight.get(i)] + value.get(i));
- }
- System.out.println(Arrays.toString(dp));
- }
- }
讲解链接:代码随想录-背包问题总结篇!
在动态规划:关于 01 背包问题,你该了解这些! 中我们讲解二维 dp 数组 01 背包先遍历物品还是先遍历背包都是可以的,且第二层 for 循环是从小到大遍历。
和动态规划:关于 01 背包问题,你该了解这些!(滚动数组) 中,我们讲解一维 dp 数组 01 背包只能先遍历物品再遍历背包容量,且第二层 for 循环是从大到小遍历。
一维 dp 数组的背包在遍历顺序上和二维 dp 数组实现的 01 背包其实是有很大差异的,大家需要注意!
说完 01 背包,再看看完全背包。
在动态规划:关于完全背包,你该了解这些! (opens new window)中,讲解了纯完全背包的一维 dp 数组实现,先遍历物品还是先遍历背包都是可以的,且第二层 for 循环是从小到大遍历。
但是仅仅是纯完全背包的遍历顺序是这样的,题目稍有变化,两个 for 循环的先后顺序就不一样了。
如果求组合数就是外层 for 循环遍历物品,内层 for 遍历背包。
如果求排列数就是外层 for 遍历背包,内层 for 循环遍历物品。
相关题目如下:
如果求最小数,那么两层 for 循环的先后顺序就无所谓了,相关题目如下:
对于背包问题,其实递推公式算是容易的,难是难在遍历顺序上,如果把遍历顺序搞透,才算是真正理解了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。