当前位置:   article > 正文

代码随想录算法训练营day46|139.单词拆分,多重背包,背包问题总结篇_hashset set = new hashset<>(worddict);

hashset set = new hashset<>(worddict);

139.单词拆分

力扣

思路:背包算法

1. 完全背包:物品是wordDict中的单词,背包是s;

2. dp数组及其下标的含义:dp[i]表示长度为 i 的字符串是否可以被拆分为 wordDict 中的单词;dp[i] = 1表示可以拆分,dp[i] = 0表示不能拆分;

3. 递推公式:当j < i时,若dp[j] = 1,且 [j,i] 区间的子串出现在字典里,那么 dp[i] = 1。

4. 初始化:dp[0] = 1(dp[0]是递推起点),下标非0的 dp[i] 初始化为false,只要没被覆盖,就说明不可拆分。

5. 遍历顺序:求排列数,外层for循环遍历背包,内层for循环遍历物品。

  1. class Solution {
  2. public boolean wordBreak(String s, List<String> wordDict) {
  3. HashSet<String> set = new HashSet<>(wordDict);
  4. int[] dp = new int[s.length()+1];
  5. dp[0] = 1;
  6. for(int i=1;i<=s.length();i++){
  7. for(int j=0;j<i && dp[i]==0;j++){//dp[i]==0 剪枝
  8. String sub = s.substring(j,i);
  9. if(set.contains(sub) && dp[j]==1){
  10. dp[i]=1;
  11. break;
  12. }
  13. }
  14. }
  15. return dp[s.length()]==1;
  16. }
  17. }

思路:回溯法+记忆化递归

使用memo数组保存每次计算的以startIndex为起点的计算结果。如果memo[startIndex]已经被标记,那么直接返回memory[startIndex]的结果。

  1. class Solution {
  2. private Set<String> set;
  3. private int[] memo;
  4. public boolean wordBreak(String s, List<String> wordDict) {
  5. memo = new int[s.length()];
  6. set = new HashSet<>(wordDict);
  7. return backTracking(s,0);
  8. }
  9. public boolean backTracking(String s, int startIndex){
  10. if(startIndex==s.length()) return true;
  11. if(memo[startIndex]==-1) return false;
  12. for(int i=startIndex;i<s.length();i++){
  13. String sub = s.substring(startIndex,i+1);
  14. if(!set.contains(sub)){//拆分出来的单词无法匹配
  15. continue;
  16. }
  17. boolean res = backTracking(s,i+1);
  18. if(res) return true;
  19. }
  20. //找遍了startIndex~s.length()也没能完全匹配,标记从startIndex开始不能找到
  21. memo[startIndex] = -1;
  22. return false;
  23. }
  24. }

多重背包

多重背包理论基础

1. 问题形式:有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求将哪些物品装入背包,可使耗费的空间不超过背包容量,且价值总和最大。

2. 思路:转化为01背包问题。每件物品最多有Mi件可用,那就把Mi件摊开,每件的数量是1。

  1. //版本一:改变物品数量为01背包格式
  2. public void testMultiPack1(){
  3. List<Integer> weight = new ArrayList<>(Arrays.asList(1, 3, 4));
  4. List<Integer> value = new ArrayList<>(Arrays.asList(15, 20, 30));
  5. List<Integer> nums = new ArrayList<>(Arrays.asList(2, 3, 2));
  6. int bagWeight = 10;
  7. for (int i = 0; i < nums.size(); i++) {
  8. while (nums.get(i) > 1) { //把物品展开为i
  9. weight.add(weight.get(i));
  10. value.add(value.get(i));
  11. nums.set(i, nums.get(i) - 1);
  12. }
  13. }
  14. int[] dp = new int[bagWeight + 1];
  15. for(int i = 0; i < weight.size(); i++) { //遍历物品
  16. for(int j = bagWeight; j >= weight.get(i); j--) { //遍历背包容量
  17. dp[j] = Math.max(dp[j], dp[j - weight.get(i)] + value.get(i));
  18. }
  19. System.out.println(Arrays.toString(dp));
  20. }
  21. }
  1. public void testMultiPack2(){
  2. int[] weight = {1, 3, 4};
  3. int[] value = {15, 20, 30};
  4. int[] nums = {2, 3, 2};
  5. int bagWeight = 10;
  6. int[] dp = new int[bagWeight + 1];
  7. for(int i = 0; i < weight.length; i++) { //遍历物品
  8. for(int j = bagWeight; j >= weight[i]; j--) { //遍历背包容量
  9. //遍历个数
  10. for (int k = 1; k <= nums[i] && (j - k * weight[i]) >= 0; k++) {
  11. dp[j] = Math.max(dp[j], dp[j - k * weight[i]] + k * value[i]);
  12. }
  13. System.out.println(Arrays.toString(dp));
  14. }
  15. }
  16. }

背包问题总结篇

​​​​​​背包总结篇​​​​​​

 背包递推公式:

1. 能否装满背包(或者最多能装多少):dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]);

2. 装满背包有几种方法:dp[j] += dp[j-nums[i]];

3. 装满背包,最大价值:dp[j] = max(dp[j],dp[j-nums[i]]+value[i]);

4. 装满背包的最小物品数目:dp[j] = min(dp[j-coins[i]]+1, dp[j]);

遍历顺序:

1. 01背包:

(1)二维dp数组,先遍历物品再遍历背包,或者先遍历背包再遍历物品都可以,且第二层for循环从小到大;

(2)一维dp数组,只能先遍历物品再遍历背包容量,且第二层for循环从大到小;

2. 完全背包:

(1)纯完全背包,先遍历物品或先遍历背包都可以,且第二层for循环从小到大。

(2)求组合数,外层for循环遍历物品,内层for遍历背包。

(3)求排列数,外层for遍历背包,内层for循环遍历物品。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/214803
推荐阅读
相关标签
  

闽ICP备14008679号