代码随想录算法训练营day46|139.单词拆分,多重背包,背包问题总结篇

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循环遍历物品。

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        HashSet<String> set = new HashSet<>(wordDict);
        int[] dp = new int[s.length()+1];
        dp[0] = 1;
        for(int i=1;i<=s.length();i++){
            for(int j=0;j<i && dp[i]==0;j++){//dp[i]==0 剪枝
                String sub = s.substring(j,i);
                if(set.contains(sub) && dp[j]==1){
                    dp[i]=1;
                    break;
                }
            }
        }
        return dp[s.length()]==1;
    }
}

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

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

class Solution {
    private Set<String> set;
    private int[] memo;
    public boolean wordBreak(String s, List<String> wordDict) {
        memo = new int[s.length()];
        set = new HashSet<>(wordDict);
        return backTracking(s,0);
    }
    public boolean backTracking(String s, int startIndex){
        if(startIndex==s.length()) return true;
        if(memo[startIndex]==-1) return false;
        for(int i=startIndex;i<s.length();i++){
            String sub = s.substring(startIndex,i+1);
            if(!set.contains(sub)){//拆分出来的单词无法匹配
                continue;
            }
            boolean res = backTracking(s,i+1);
            if(res) return true;
        }
        //找遍了startIndex~s.length()也没能完全匹配,标记从startIndex开始不能找到
        memo[startIndex] = -1;
        return false;
    }
}

多重背包

多重背包理论基础

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

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

//版本一:改变物品数量为01背包格式
public void testMultiPack1(){
    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));
    }
}
public void testMultiPack2(){
    int[] weight = {1, 3, 4};
    int[] value = {15, 20, 30};
    int[] nums = {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--) { //遍历背包容量
            //遍历个数
            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));
        }
    }
}

背包问题总结篇

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

 背包递推公式:

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循环遍历物品。

代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值