Day46|139.单词拆分 、多重背包理论基础、背包问题总结

news2024/9/21 14:30:18

139.单词拆分 

1.题目:

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

 示例 1:

输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。
示例 2:

输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。
     注意,你可以重复使用字典中的单词。
示例 3:

输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false

https://leetcode.cn/problems/word-break

2.思路:

单词就是物品,字符串s就是背包,单词能否组成字符串s,就是问物品能不能把背包装满。

拆分时可以重复使用字典中的单词,说明就是一个完全背包

动规五部曲分析如下:

1.确定dp数组以及下标的含义

dp[i] : 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词

2.确定递推公式

如果确定dp[j] 是true,且 [j, i] 这个区间的子串出现在字典里,那么dp[i]一定是true。(j < i )。

所以递推公式是 if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) 那么 dp[i] = true。

3.dp数组如何初始化

从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false了。

那么dp[0]有没有意义呢?

dp[0]表示如果字符串为空的话,说明出现在字典里。

但题目中说了“给定一个非空字符串 s” 所以测试数据中不会出现i为0的情况,那么dp[0]初始为true完全就是为了推导公式。

下标非0的dp[i]初始化为false,只要没有被覆盖说明都是不可拆分为一个或多个在字典中出现的单词。

4.确定遍历顺序

题目中说是拆分为一个或多个在字典中出现的单词,所以这是完全背包。

还要讨论两层for循环的前后顺序。

如果求组合数就是外层for循环遍历物品,内层for遍历背包

如果求排列数就是外层for遍历背包,内层for循环遍历物品

我在这里做一个总结:

求组合数:动态规划:518.零钱兑换II (opens new window)

求排列数:动态规划:377. 组合总和 Ⅳ (opens new window)、动态规划:70. 爬楼梯进阶版(完全背包) (opens new window)

求最小数:动态规划:322. 零钱兑换 (opens new window)、动态规划:279.完全平方数(opens new window)

而本题其实我们求的是排列数,为什么呢。 拿 s = "applepenapple", wordDict = ["apple", "pen"] 举例。

"apple", "pen" 是物品,那么我们要求 物品的组合一定是 "apple" + "pen" + "apple" 才能组成 "applepenapple"。

"apple" + "apple" + "pen" 或者 "pen" + "apple" + "apple" 是不可以的,那么我们就是强调物品之间顺序。

所以说,本题一定是 先遍历 背包,再遍历物品。

5.举例推导dp[i]

以输入: s = "leetcode", wordDict = ["leet", "code"]为例,dp状态如图:

dp[s.size()]就是最终结果。

3.代码:

 public boolean wordBreak(String s, List<String> wordDict) {
        //
        HashSet<String> hashset=new HashSet<>(wordDict);
        boolean[] dp=new boolean[s.length()+1];
        dp[0]=true;
        for(int i=1;i<=s.length();i++){
            for(int j=0;j<i && !dp[i];j++){
                if(hashset.contains(s.substring(j,i)) && dp[j]){
                    dp[i]=true;
                }
            }
        }
        return dp[s.length()];
    }

多重背包理论基础

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

多重背包和01背包是非常像的, 为什么和01背包像呢?

每件物品最多有Mi件可用,把Mi件摊开,其实就是一个01背包问题了。

例如:

背包最大重量为10。

物品为:

重量价值数量
物品01152
物品13203
物品24302

问背包能背的物品最大价值是多少?

和如下情况有区别么?

重量价值数量
物品01151
物品01151
物品13201
物品13201
物品13201
物品24301
物品24301

毫无区别,这就转成了一个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));
    }
}

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));
        }
    }
}

背包问题总结

几种常见的背包,其关系如下:

通过这个图,可以很清晰分清这几种常见背包之间的关系。

五部动规

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

递推公式

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

  • 动态规划:416.分割等和子集(opens new window)
  • 动态规划:1049.最后一块石头的重量 II(opens new window)

2.问装满背包有几种方法:dp[j] += dp[j - nums[i]] ,对应题目如下:

  • 动态规划:494.目标和(opens new window)
  • 动态规划:518. 零钱兑换 II(opens new window)
  • 动态规划:377.组合总和Ⅳ(opens new window)
  • 动态规划:70. 爬楼梯进阶版(完全背包)(opens new window)

3.问背包装满最大价值:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); ,对应题目如下:

  • 动态规划:474.一和零(opens new window)

4.问装满背包所有物品的最小个数:dp[j] = min(dp[j - coins[i]] + 1, dp[j]); ,对应题目如下:

  • 动态规划:322.零钱兑换(opens new window)
  • 动态规划:279.完全平方数(opens new window)

遍历顺序

01背包

在动态规划:关于01背包问题,你该了解这些! (opens new window)中我们讲解二维dp数组01背包先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历。

和动态规划:关于01背包问题,你该了解这些!(滚动数组) (opens new window)中,我们讲解一维dp数组01背包只能先遍历物品再遍历背包容量,且第二层for循环是从大到小遍历。

一维dp数组的背包在遍历顺序上和二维dp数组实现的01背包其实是有很大差异的,大家需要注意!

完全背包

在动态规划:关于完全背包,你该了解这些! (opens new window)中,讲解了纯完全背包的一维dp数组实现,先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历。

但是仅仅是纯完全背包的遍历顺序是这样的,题目稍有变化,两个for循环的先后顺序就不一样了。

如果求组合数就是外层for循环遍历物品,内层for遍历背包

如果求排列数就是外层for遍历背包,内层for循环遍历物品

相关题目如下:

  • 求组合数:动态规划:518.零钱兑换II(opens new window)
  • 求排列数:动态规划:377. 组合总和 Ⅳ (opens new window)、动态规划:70. 爬楼梯进阶版(完全背包)(opens new window)

如果求最小数,那么两层for循环的先后顺序就无所谓了,相关题目如下:

  • 求最小数:动态规划:322. 零钱兑换 (opens new window)、动态规划:279.完全平方数(opens new window)

对于背包问题,其实递推公式算是容易的,难是难在遍历顺序上,如果把遍历顺序搞透,才算是真正理解了。​​​​​​​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/733315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TiDB 7.1 资源管控验证测试

作者&#xff1a; dba-kit 原文来源&#xff1a; https://tidb.net/blog/9cd7dcb3 〇、背景 我们线上使用环境和李文杰大佬比较类似&#xff0c;我这里就不赘述了&#xff0c;大家可以看 专栏 - TiDB v7.1.0 跨业务系统多租户解决方案 | TiDB 社区 &#xff0c;这里比较清…

PyQt---------PyQt组件的学习

1.QLabel组件 QLabel用于显示文本或图像&#xff0c;不提供用户交互功能&#xff0c;标签的视觉外观可以以各种方式配置。 举个例子吧 import sys from PyQt6.QtCore import Qt from PyQt6.QtWidgets import QApplication, QLabel, QMainWindowclass MainWindow(QMainWindow…

大厂C++题第1辑——虚函数七题精讲之2:虚函数的作用机制

一、虚函数的常见应用场景&#xff1b; 二、发挥虚函数作用的语法&#xff1b; 三、虚函数的实现机制&#xff1b; 四、虚函数的性能影响。 题2-虚函数的常见应用场景 上一节我们讲了虚函数的作用&#xff0c;同时也演示了虚函数发挥作用的路径之一&#xff1a; 一个派生类对…

Docker 私有仓库 harbor 搭建

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…

Vue操作Cookie

这里用的js-cookie。 很简单&#xff0c;安装一下就可以使用了。 npm install js-cookie --save 使用示例&#xff1a; import Cookies from js-cookieexport default {name: YourComponent,methods: {setCookie() {// 设置一个名为 name 的cookie&#xff0c;值为 value&a…

聚焦信息技术发展,博睿数据受邀出席产业链供需对接深度行北京站活动

7月6日&#xff0c;以“广聚群链 湾区启航”为主题的产业链供需对接深度行北京站活动圆满落幕。本次活动吸引了来自北京和广东的多家知名企业参与&#xff0c;博睿数据受邀出席了本次活动&#xff0c;同时携核心产品一体化智能可观测平台Bonree ONE参展&#xff0c;展示博睿数据…

Nginx配置springboot+vue项目http跳转https

java生成证书 添加依赖 <dependency><groupId>org.bouncycastle</groupId><artifactId>bcpkix-jdk15on</artifactId><version>1.69</version></dependency> import org.bouncycastle.asn1.ASN1Encodable; import org.bounc…

易微联2.4G通断器添加到手机步骤

蓝牙款无WIFI&#xff0c;按住通断器上的按钮&#xff0c;会先闪一下&#xff0c;再闪两下。闪一下的时候连手机&#xff0c;闪两下清码。 手机上打开易微联app&#xff0c;依次点击加号/轻智能遥控器/单按键遥控器/添加完成。 返回打开刚才添加的开关&#xff0c;在通断器闪…

基于Spring Boot的医院信息管理系统设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于Spring Boot的医院信息管理系统设计与实现 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 后端&#xff1a;Java springboot框架 mybatis 数据库&#xff1a;mysql5.7 开发工具:IDEA…

Apollo星火计划城市交通大赛600分,断头路,特殊车辆绕行,借道绕行

现在解决了前六题&#xff0c;可以拿到600分&#xff0c;有兴趣一起讨论的可以私聊我交流一下。

Linux命令(41)之top

Linux命令之top 1.top介绍 linux命令top是用来实时监测服务器资源的使用状况&#xff0c;包含进程、cpu、内存等等 2.top用法 top [参数] top常用参数 参数说明-d屏幕刷新时间间隔-i<time>设置刷新时间间隔-u<user>指定用户名-p<pid>指定进程号 top命令中…

Android平台GB28181设备接入技术探讨

GB/T28181技术背景 在此之前&#xff0c;我们先对协议规范做个简单了解&#xff1a;GB28181协议是一种用于视频监控系统互联互通的国际标准&#xff0c;它定义了视频监控系统中的设备间如何进行通信、交换数据和协调控制。以下是GB28181协议的一些主要内容&#xff1a; 设备互…

有哪些数据结构与算法是程序员必须要掌握的?——“数据结构与算法”

一&#xff1a;引言 作为IT程序员&#xff0c;学习算法的原因主要有以下几点&#xff1a; 提升问题解决能力&#xff1a;算法可以帮助程序员分析、优化和解决复杂问题。了解算法原理和实现方式将有助于程序员更快地找到合适的解决方案。这对于解决实际工作中的问题是非常有帮助…

基于STM32FFT(快速傅里叶变换)音频频谱显示功能实现

+ v hezkz17进数字音频系统研究开发交流答疑 一实验效果 二 设计过程 要用C语言实现STM32频谱显示功能,可以按照以下步骤进行操作: 1 确保已经安装好了适当的开发环境和工具链,例如Keil MDK或者GCC工具链。 2 创建一个新的STM32项目,并选择适合的MCU型号。 3 配置G…

es8.8 集群安装笔记

es8.8 集群安装笔记 配置集群第一步 修改配置文件 本次安装使用centos8 3节点安装&#xff1a; 192.168.182.142 192.168.182.143 192.168.182.144 官网 可以查看详细的安装&#xff0c;安装步骤比较简单 https://www.elastic.co/guide/en/elasticsearch/reference/8.8/rpm.htm…

使用gradio库的Plot模块创建交互式绘图界面

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

Mongodb-5.0.18-zip下载与安装

1.下载地址 Download MongoDB Community Server | MongoDB 2.创建一个文件夹和master.cfg的文件 说明&#xff1a;目的是让mongodb存放数据库的位置在mongodb文件里面。 2.1创建名为mongodb的文件夹 2.2master.cfg 说明&#xff1a;在mongodb5.0.18目录下创建master.cfg。 …

DeepSpeed使用体会

现在的模型越来越大&#xff0c;动辄几B甚至几百B。但是显卡显存大小根本无法支撑训练推理。例如&#xff0c;一块RTX2090的10G显存&#xff0c;光把模型加载上去&#xff0c;就会OOM&#xff0c;更别提后面的训练优化。 作为传统pytorch Dataparallel的一种替代&#xff0c;D…

Spring Cloud Alibaba 之 Nacos精讲

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

ChatGPT炒股:批量自动提取股票公告中的表格并合并数据

首先&#xff0c;在ChatGPT中输入提示词&#xff1a; 写一段Python代码&#xff1a; F盘文件夹“新三板 2023年日常性关联交易20230704”中很多个PDF文件&#xff0c;用 Tabula提取这些PDF文件中第1页中的第2个表格&#xff0c;然后保存到表格文件中&#xff0c;文件标题名和…