Day 46 139.单词拆分

单词拆分

给定一个非空字符串 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

​ 单词视为物品,字符串视为背包,又因为可以重复使用,所以是完全背包;

​ 动规五部曲:

​ 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]一定是true,否则递推下去后面都都是false了;

​ 那么dp[0]有没有意义呢?dp[0]表示如果字符串为空的话,能否在字典中找到,很明显应该是false;

​ 但题目中说了“给定一个非空字符串 s” 所以测试数据中不会出现i为0的情况,那么dp[0]怎样定义其实无所谓了;

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

​ 其实很多时候都会出现这种dp[0]赋值和意义不一致的情况,以递推公式为主;

​ 4.确定遍历顺序

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

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

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

​ 而本题其实求的是排列数, 拿 s = “applepenapple”, wordDict = [“apple”, “pen”] 举例;

​ “apple”, “pen” 是物品,那么我们要求 物品的组合一定是 “apple” + “pen” + “apple” 才能组成 “applepenapple”;

​ “apple” + “apple” + “pen” 或者 “pen” + “apple” + “apple” 是不可以的,此处就是强调物品之间顺序;

​ 所以一定是先遍历背包,再遍历物品

	for(int i = 1; i < s.size(); i++) {for(int j = 0; j < i; j++){string tempWord = s.substr(j, i - 1);if(dict.find(tempWord) != dict.end() && dp[j] == true){dp[i] = true;}}}

​ 5.打印dp数组:

class Solution {
public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string> wordSet(wordDict.begin(), wordDict.end());//转化为unordered_set(即wordSet)的原因是为了提高查找效率vector<bool> dp(s.size() + 1, 0);dp[0] = true;for(int i = 1; i <= s.size(); i++) {for(int j = 0; j < i; j++){string tempWord = s.substr(j, i - j);if(wordSet.find(tempWord) != wordSet.end() && dp[j] == true){dp[i] = true;}}}return dp[s.size()];}
};

​ 时间复杂度:O(n^3),因为substr返回子串的副本是O(n)的复杂度(这里的n是substring的长度)

​ 空间复杂度:O(n)

多重背包

​ 多重背包本质上可以视为01背包,因为数量仍然是有限个;

​ 每件物品最多有M件可用,把M件摊开,其实01背包问题了;

​ 但是不能完全按照01背包的代码来写,因为vector扩容是一件非常耗时的事情;

​ 递推公式写成如下的形式,把每种商品遍历的个数放在01背包里面在遍历一遍,再递推,就解决了:

d p [ j ] = m a x ( d p [ j ] , d p [ j − k ∗ w e i g h t [ i ] ] + k ∗ v a l u e [ i ] ) dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]) dp[j]=max(dp[j],dp[jkweight[i]]+kvalue[i])

#include<iostream>
#include<vector>
using namespace std;
int main() {int bagWeight,n;cin >> bagWeight >> n;vector<int> weight(n, 0);vector<int> value(n, 0);vector<int> nums(n, 0);for (int i = 0; i < n; i++) cin >> weight[i];for (int i = 0; i < n; i++) cin >> value[i];for (int i = 0; i < n; i++) cin >> nums[i];vector<int> dp(bagWeight + 1, 0);for(int i = 0; i < n; 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]);}}}cout << dp[bagWeight] << endl;
}

​ 时间复杂度:O(m × n × k),m:物品种类个数,n背包容量,k单类物品数量

背包问题总结

递推公式

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

​ 动态规划:416.分割等和子集(opens new window)

​ 动态规划:1049.最后一块石头的重量 II(opens new window)

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

​ 动态规划:494.目标和(opens new window)

​ 动态规划:518. 零钱兑换 II(opens new window)

​ 动态规划:377.组合总和Ⅳ(opens new window)

​ 动态规划:70. 爬楼梯进阶版(完全背包)(opens new window)

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

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

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

​ 动态规划:322.零钱兑换(opens new window)

​ 动态规划:279.完全平方数

遍历顺序

对于01背包

​ 二维dp数组的两个for遍历的先后循序是可以颠倒的;

​ 一维dp数组的两个for循环先后循序一定是先遍历物品,再遍历背包容量

​ 对于完全背包

​ 因为dp[j] 是根据下标j之前所对应的dp[j]计算出来的;

​ 只要保证下标j之前的dp[j]都是经过计算的就可以了,颠倒是不会影响结果的;

​ 但如果题目有所变动,不再是求纯完全背包问题:

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

for循环先后循序一定是先遍历物品,再遍历背包容量

​ 对于完全背包

​ 因为dp[j] 是根据下标j之前所对应的dp[j]计算出来的;

​ 只要保证下标j之前的dp[j]都是经过计算的就可以了,颠倒是不会影响结果的;

​ 但如果题目有所变动,不再是求纯完全背包问题:

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小红书自动私信获客,打造个人品牌

在当今这个内容为王、社交至上的时代&#xff0c;小红书作为新兴的社交电商平台&#xff0c;凭借其独特的社区氛围和强大的种草能力&#xff0c;成为了众多KOL、商家以及个人品牌打造的首选平台。想要在小红书上脱颖而出&#xff0c;精准引流获客&#xff0c;利用自动私信功能不…

国外新闻媒体推广:多元化媒体分发投放-大舍传媒

前言 &#xff1a;随着全球化的进程&#xff0c;国外新闻市场呈现出快速发展的趋势。在这个趋势下&#xff0c;国外新闻媒体推广成为了各行业企业宣传业务的重要一环。本文将重点介绍大舍传媒的多元化媒体分发投放服务&#xff0c;以及对国外新闻媒体推广的意义。 1. 多元化媒…

linux内核:持续更新

内核源码树 COPYING文件是内核许可证&#xff0c;CREDITS是开发了很多内核代码的开发者列表&#xff0c;MAINTAINERS是维护者列表&#xff0c;它们负责维护内核子系统和驱动程序&#xff0c;makefile是基本内核的makefile 向内核插入驱动模块 命令&#xff1a;insmod xxx.ko …

网络库-POCO介绍

1.简介 POCO C Libraries 提供一套 C 的类库用以开发基于网络的可移植的应用程序&#xff0c;它提供了许多模块&#xff0c;包括网络编程、文件系统访问、线程和并发、数据库访问、XML处理、配置管理、日志记录等功能。Poco库的设计目标是易于使用、高度可定制和可扩展。 包含…

LeetCode2390从字符串中移除星号

题目描述 给你一个包含若干星号 * 的字符串 s 。在一步操作中&#xff0c;你可以&#xff1a;选中 s 中的一个星号。移除星号 左侧 最近的那个 非星号 字符&#xff0c;并移除该星号自身。返回移除 所有 星号之后的字符串。注意&#xff1a;生成的输入保证总是可以执行题面中描…

EUCR-30S电机保护器施耐德EOCR

​EOCR主要产品有电子式电动机保护继电器&#xff0c;电子式过电流继电器&#xff0c;电子式欠电流继电器&#xff0c;电子式欠电压继电器&#xff0c;其它保护和监视装置&#xff0c;电流互感器。 电器密集型设计 ■ 二个集成组装电流互感器 ■ 欠载保护&#xff08;空转保护…

2024.5.9 关于 SpringCloud —— Nacos 的安装与配置

目录 Windos 安装步骤 docker 启动 nacos Windos 安装步骤 1&#xff09;点击下方链接&#xff0c;进入并访问 nacos 官网 Nacos官网 | Nacos 官方社区 | Nacos 下载 | Nacos 2&#xff09;按照下图箭头指示下载对应版本的压缩包 3&#xff09;此时我们将得到一个压缩包&…

2024国考行测、申论资料大全,做好备考真的很重要!

1. 国考是什么? 国考,全称国家公务员考试,是选拔国家公务员的重要途径。通过国考,你将有机会进入政府部门,为国家建设贡献力量。 2. 国考难在哪里? 国考之所以难,主要体现在以下几个方面: (1) 竞争激烈 每年国考报名人数都在百万以上,而录取率却不足2%。千军万马过独木桥…

保研机试之【设备驱动程序】

B选项&#xff1a; 综上&#xff0c;我认为这道题选择D~

整合Tess4J图文识别技术

仓库地址&#xff1a;https://gitee.com/z3inc/tess4j-demo.git 1. OCR图文识别介绍 OCR&#xff08;全称 Optical Character Recognition&#xff0c;直译为光学字符识别&#xff09;用于图片文字识别&#xff0c;例如 提取图片中车牌号等等。 Java中实现OCR的技术方案有&…

【C++】详解C++的模板

目录 概念 ​编辑 语法 函数模板 类模板 非类型模板参数 模板的特化 函数模板特化 类模板特化 全特化 偏特化 分离编译 概念 模板是C中非常厉害的设计&#xff0c;模板把通用的逻辑剥离出来&#xff0c;让不同的数据类型可以复用同一种模板的逻辑&#xff0c;甚至可以…

Nginx的.conf文件路径配置

nginx服务器文件目录如下图所示 nginx服务器的配置文件位于conf文件夹下&#xff0c;名称为nginx.conf&#xff1b;conf文件夹下文件目录如下所示&#xff1a; nginx.conf配置文件如下&#xff0c;各参数含义详见备注&#xff1a; server { listen 1880; #端口号…