代码随想录day40|139单词拆分、多重背包、背包总结|01笔记

96 阅读2分钟
  • 139单词拆分

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • wordDict中元素相当于硬币,字符串s相当于背包,目的是装满背包。元素可以无限次重复使用,所以是完全背包问题。
  • 讲解观后感

  • dp[i] : 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词
  • 递推公式是 if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) 那么 dp[i] = true。
  • dp[0]一定要为true
  • 本题的s一定是固定顺序的,我们要得到准确的顺序,本题一定是 先遍历背包,再遍历物品
  • 解题代码

  •     func wordBreak(s string,wordDict []string) bool  {
        	wordDictSet := make(map[string]bool)
        	for _, w := range wordDict {
        		wordDictSet[w] = true
        	}
        	dp := make([]bool, len(s)+1)
        	dp[0] = true
        	for i := 1; i <= len(s); i++ {
        		for j := 0; j < i; j++ {
        			if dp[j] && wordDictSet[s[j:i]] { 
        				dp[i] = true
        				break
        			}
        		}
        	}
        	return dp[len(s)]
        }
        // 转化为 求装满背包s的前几位字符的方式有几种
        func wordBreak(s string, wordDict []string) bool {
        	// 装满背包s的前几位字符的方式有几种
        	dp := make([]int, len(s)+1)
        	dp[0] = 1
        	for i := 0; i <= len(s); i++ { // 背包
        		for j := 0; j < len(wordDict); j++ { // 物品
        			if i >= len(wordDict[j]) && wordDict[j] == s[i-len(wordDict[j]):i] {
        				dp[i] += dp[i-len(wordDict[j])]
        			}
        		}
        	}
        
        	return dp[len(s)] > 0
        }
    
  • 时间复杂度:O(n^3),因为substr返回子串的副本是O(n)的复杂度(这里的n是substring的长度)
  • 空间复杂度:O(n)
  • 多重背包

  • 代码随想录 (programmercarl.com)
  • 代码示意

  • 两种思路,一种是将固定数量的某种物品,当成不同的物品,相同的属性,全部压入元素集。
  •     	package theory
        
        import "log"
        
        // 多重背包可以化解为 01 背包
        func multiplePack(weight, value, nums []int, bagWeight int) int {
        
        	for i := 0; i < len(nums); i++ {
        		for nums[i] > 1 {
        			weight = append(weight, weight[i])
        			value = append(value, value[i])
        			nums[i]--
        		}
        	}
        	log.Println(weight)
        	log.Println(value)
        
        	res := make([]int, bagWeight+1)
        	for i := 0; i < len(weight); i++ {
        		for j := bagWeight; j >= weight[i]; j-- {
        			res[j] = getMax(res[j], res[j-weight[i]]+value[i])
        		}
        		log.Println(res)
        	}
        
        	return res[bagWeight]
        }
    
  • 一种是在遍历过程中限制次数
  • C++
  •     void test_multi_pack() {
            vector<int> weight = {1, 3, 4};
            vector<int> value = {15, 20, 30};
            vector<int> nums = {2, 3, 2};
            int bagWeight = 10;
            vector<int> dp(bagWeight + 1, 0);
        
        
            for(int i = 0; i < weight.size(); 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] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);
                    }
                }
                // 打印一下dp数组
                for (int j = 0; j <= bagWeight; j++) {
                    cout << dp[j] << " ";
                }
                cout << endl;
            }
            cout << dp[bagWeight] << endl;
        }
        int main() {
            test_multi_pack();
        }
    
  • 背包总结

  • 代码随想录 (programmercarl.com)