代码随想录算法训练营第46天| Leetcode 139.单词拆分、卡码网 56. 携带矿石资源(附带多重背包的基本解法和优化)

news2024/9/28 21:23:24

文章目录

    • Leetcode 139.单词拆分
    • 卡码网 56. 携带矿石资源
      • 方法一: 分组转化成01背包
      • 方法二: 转化成01背包+完全背包(基于方法一的小优化)
      • 方法三: 二进制优化(优化了方法一的分组方式)

Leetcode 139.单词拆分

题目链接:Leetcode 139.单词拆分
题目描述: 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
思路: 由于单词可以重复使用,并且要求正确顺序,因此可以联想到完全背包中的求排列问题。

  • dp[i] : 字符串长度为i的话,dp[i]true,表示可以拆分为一个或多个在字典中出现的单词。
  • 递推公式:如果截取的单词[i - sz, sz]等于word并且dp[i - sz] == true,则dp[i] = true
  • 初始化:dp[0] = ture
  • 遍历顺序:先遍历背包,后遍历物品。

代码如下:

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        vector<bool> dp(s.size() + 5);
        dp[0] = true;
        // 完全背包求排列问题
        for (int i = 1; i <= s.size(); i++) // 先遍历背包
            for (auto& word : wordDict) {   // 后遍历物品
                int sz = word.size();
                // 首先背包容量要大于单词大小
                // 其次,如果截取的单词[i-sz,sz]等于word并且dp[i-sz]==true,则dp[i]=true
                if (i >= sz && s.substr(i - sz, sz) == word) {
                    dp[i] = dp[i] || dp[i - sz];
                }
            }
        return dp[s.size()];
    }
};
  • 时间复杂度 O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度 O ( n ) O(n) O(n)

卡码网 56. 携带矿石资源

题目链接:卡码网 56. 携带矿石资源
在这里插入图片描述

思路: 这道题是多重背包的模板题。首先观察多重背包的特点是每件物品的数量不相同,其余的条件和01背包和完全背包很像,那能不能将其转化成它们呢?答案是可以。

方法一: 分组转化成01背包

由于多重背包每件物品数量不相同,不知道一种占用空间 w ,价值为 v,数量为 s 的物品该拿多少件,因此我们就把该拿多少件枚举一下,假设为 k1 <= k <= s ,然后我们就把问题看成仅有一件的占用空间k * w ,价值为k * v的物品该不该拿。
代码如下:

#include <iostream>
#include <vector>
 
using namespace std;
 
const int N = 1e4 + 5;
 
int w[N],v[N],k[N];
int dp[N];
int n,m;
 
int main()
{
    cin >> n >> m;//背包大小和物品数量
    for(int i = 1; i <= m; i ++ ) cin >> w[i];
    for(int i = 1; i <= m; i ++ ) cin >> v[i];
    for(int i = 1; i <= m; i ++ ) cin >> k[i];
    //转化成01背包
    for(int i = 1; i <= m; i ++ )//遍历物品
        for(int j = n; j >= w[i]; j -- )//遍历背包
            //遍历个数
            for(int num = 1; num <= k[i] && j - num * w[i] >= 0; num ++ )
                dp[j] = max(dp[j], dp[j - num * w[i]] + num * v[i]);
                 
    cout << dp[n];
    return 0;
}
  • 时间复杂度 O ( n 3 ) O(n^3) O(n3)
  • 空间复杂度 O ( n ) O(n) O(n)

方法二: 转化成01背包+完全背包(基于方法一的小优化)

我们发现,如果k个物品的总重量大于等于背包的最大容量,说明在当前大小的背包容量下,该物品有无限个和只有k个的效果是相同的,这部分物品就转化成了完全背包问题。

为什么要转换成完全背包?我们看方法一转化成01背包是需要枚举一下拿多少件的,而转化为完全背包是不需要枚举多少件的,可以拿我们就拿,所以在时间上会有一些优化。(尽管时间复杂度不变)

代码如下:

#include <iostream>
#include <vector>
 
using namespace std;
 
const int N = 1e4 + 5;
 
int w[N],v[N],k[N];
int dp[N];
int n,m;
 
int main()
{               
    cin >> n >> m;//背包大小和物品数量
    for(int i = 1; i <= m; i ++ ) cin >> w[i];
    for(int i = 1; i <= m; i ++ ) cin >> v[i];
    for(int i = 1; i <= m; i ++ ) cin >> k[i];
    //转化成01背包+完全背包
    for(int i = 1; i <= m; i ++ )//遍历物品
    {
        if(k[i] * w[i] >= n)//如果不能把某个物品全部一次性装下,则可转化为完全背包
        {
            for(int j = w[i]; j <= n; j ++ )
                dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
                 
        }else
        {
            for(int j = n; j >= w[i]; j -- )//遍历背包
                //遍历个数
                for(int num = 1; num <= k[i] && j - num * w[i] >= 0; num ++ )
                    dp[j] = max(dp[j], dp[j - num * w[i]] + num * v[i]);
                 
        }
         
    }
                 
    cout << dp[n];
    return 0;
}
  • 时间复杂度 O ( n 3 ) O(n^3) O(n3)
  • 空间复杂度 O ( n ) O(n) O(n)

方法三: 二进制优化(优化了方法一的分组方式)

我们发现利用从 1 1 1 2 2 2 4 4 4…… 2 n 2^n 2n可以枚举出 [ 0 , 2 n − 1 ] [0,2^n-1] [0,2n1]的所有数字(利用等比数列求和可以证明),因此可以不用像方法一那样依次枚举每个数字,本题数据范围是 1 0 4 10^4 104,而 2 13 = 8192 2^{13}=8192 213=8192,也就是每个数字最多分为 14 14 14组即可,不必依次枚举k,大大降低了时间复杂度。
代码如下:

#include <iostream>
#include <vector>

using namespace std;

const int N = 1e4 + 5;
const int M = 13 * N + 5;//根据数据范围,一个数最多拆13次,因此要比原来多开一些空间
int w[N],v[N],k[N];
int W[M],V[M];//用来记录分组之后的物品重量和价值
int dp[N];
int n,m;

int main()
{               
    cin >> n >> m;//背包大小和物品数量
    for(int i = 1; i <= m; i ++ ) cin >> w[i];
    for(int i = 1; i <= m; i ++ ) cin >> v[i];
    for(int i = 1; i <= m; i ++ ) cin >> k[i];
    //将物品数量按照(1,2,4...2^n)分组,然后转化为01背包(优化了遍历次数)
    int cnt = 0;//记录物品数量
    for(int i = 1; i <= m; i ++ )//分组过程
    {
        int num = 1;
        while(num <= k[i])
        {
            cnt ++ ;
            W[cnt] = num * w[i];
            V[cnt] = num * v[i];
            k[i] -= num;
            num *= 2;
        }
        if(k[i])//剩下的直接放入
        {
            cnt ++ ;
            W[cnt] = k[i] * w[i];
            V[cnt] = k[i] * v[i];
        }
    }
    //01背包过程
    for(int i = 1;i <= cnt; i ++ )
        for(int j = n; j >= W[i]; j -- ){
            dp[j] = max(dp[j], dp[j - W[i]] + V[i]);
        }
            
    //输出
    cout << dp[n];
    return 0;
}
  • 时间复杂度 O ( n 2 l o g n ) O(n^2logn) O(n2logn)
  • 空间复杂度 O ( n ) O(n) O(n)

总结: 遇到一个新问题首先我们可以思考是否可以利用已有知识来解决,就像多重背包的解法就是基于01背包和完全背包。

最后,如果文章有错误,请在评论区或私信指出,让我们共同进步!

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

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

相关文章

基于springboot的宠物咖啡馆平台的设计与实现论文

基于Spring Boot的宠物咖啡馆平台的设计与实现 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于Spring Boot的宠物咖啡馆平台的设计与实现的开发全过程。通过分析基于Spring Boot的宠物咖啡馆平台的设计与…

【Scratch画图100例】图49-scratch绘制直角风车 少儿编程 scratch编程画图案例教程 考级比赛画图集训案例

目录 scratch绘制直角风车 一、题目要求 1、准备工作 2、功能实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、实现流程 1、案例分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 …

leetcode第 387 场周赛总结

很久没打周赛了&#xff0c;这周开始恢复 这次周赛&#xff0c;题目比较简单&#xff0c;第三道题有点浪费了时间&#xff0c;思路是对的&#xff0c;但是被我把问题复杂化了。 晚上来写题解和总结

YOLOv9有效提点|加入SGE、Ge、Global Context、GAM等几十种注意力机制(四)

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文只有代码及注意力模块简介&#xff0c;YOLOv9中的添加教程&#xff1a;可以看这篇文章。 YOLOv9有效提点|加入SE、CBAM、ECA、SimA…

C++入门全集(3):类与对象【中】

一、前言 经过上一篇文章的学习&#xff0c;我们知道类中由成员变量和成员函数组成 本章的内容&#xff0c;就围绕类的6个默认成员函数展开讲解 如果一个类中什么都没有&#xff0c;简称为空类 class Date {};然而&#xff0c;空类真的像表面一样什么都没有吗&#xff1f;不…

HBM(High Bandwidth Memory)

选择正确的高带宽内存 构建高性能芯片的选择越来越多&#xff0c;但附加内存的选择却几乎没有变化。为了在汽车、消费和超大规模计算中实现最大性能&#xff0c;选择取决于一种或多种 DRAM&#xff0c;而最大的权衡是成本与速度。 尽管多年来人们一直在努力用更快、更便宜或更…

【MySQL】索引(重点)-- 详解

一、索引 没有索引&#xff0c;可能会有什么问题&#xff1f; 索引 &#xff1a;提高数据库的性能&#xff0c;索引是物美价廉的东西了。不用加内存&#xff0c;不用改程序&#xff0c;不用调 sql &#xff0c;只要执行正确的 create index &#xff0c;查询速度就可能提高成…

06.QT信号和槽-1

一、信号和槽概述 在Qt中&#xff0c;用户和控件的每次交互过程称为一个事件。比如"用户点击按钮"是一个事件&#xff0c;"用户关闭窗口"也是一个事件。每个事件都会发出一个信号&#xff0c;例如用户点击按钮会发出"按钮被点击"的信号&#xff…

武汉灰京文化:多样化推广与创新引领游戏行业

作为专业的游戏推广服务商&#xff0c;武汉灰京文化注重多样化的推广策略&#xff0c;通过与各大媒体、社交平台和游戏社区建立紧密的合作关系&#xff0c;为游戏企业提供全方位的推广服务。他们通过精确的广告投放、内容创作和社交媒体互动等方式&#xff0c;将游戏信息传播给…

MySQL 核心模块揭秘 | 07 期 | 二阶段提交 (1) prepare 阶段

二阶段提交的 prepare 阶段&#xff0c;binlog 和 InnoDB 各自会有哪些动作&#xff1f; 本文基于 MySQL 8.0.32 源码&#xff0c;存储引擎为 InnoDB。 1. 二阶段提交 二阶段提交&#xff0c;顾名思义&#xff0c;包含两个阶段&#xff0c;它们是&#xff1a; prepare 阶段。…

xxl-job--02--可视化界面各功能详细介绍

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 可视化界面1 新增执行器2.新增任务**执行器**&#xff1a;**任务描述**&#xff1a;**路由策略**&#xff1a;**Cron**&#xff1a;cron表达式**运行模式**JobHandl…

YOLO算法

YOLO介绍 YOLO&#xff0c;全称为You Only Look Once: Unified, Real-Time Object Detection&#xff0c;是一种实时目标检测算法。目标检测是计算机视觉领域的一个重要任务&#xff0c;它不仅需要识别图像中的物体类别&#xff0c;还需要确定它们的位置。与分类任务只关注对…

【Python】进阶学习:pandas--query()用法详解

&#x1f4da;【Python】进阶学习&#xff1a;pandas–query()用法详解 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希…

Docker知识点总结

二、Docker基本命令&#xff1a; Docker支持CentOs 6 及以后的版本; CentOs7系统可以直接通过yum进行安装&#xff0c;安装前可以 1、查看一下系统是否已经安装了Docker: yum list installed | grep docker 2、安装docker&#xff1a; yum install docker -y -y 表示自动确认…

RH850P1X芯片学习笔记-Generic Timer Module -ATOM

文章目录 ARU-connected Timer Output Module (ATOM)OverviewGLOBAL CHANNEL CONTROL BLOCK ATOM Channel architectureATOM Channel modesSOMP-Signal Output Mode PWMSOMP - ARUSOMC-Signal Output Mode CompareSOMC - ARUSOMC – COMPARE COMMANDSOMC – OUTPUT ACTIONATOM …

【如何像网吧一样弄个游戏菜单在家里】

GGmenu 个人家庭版游戏、应用管理 桌面图标管理器

【笔试强训错题选择题】Day5.习题(错题)解析

文章目录 前言 错题题目 错题解析 总结 前言 错题题目 1. ​ ​ 2. 3. ​ 4. ​ 5. ​ 错题解析 1. 移位运算符的使用 2. 3. 4. 5. 总结

应用机器学习回归离群值处理

异常值可能会破坏机器学习模型的运转&#xff0c;导致结果出现偏差并影响准确性。在这篇博文中&#xff0c;我们将深入研究应用机器学习领域&#xff0c;并探索使用 Python 识别和处理异常值的有效技 了解异常值 离群值是与数据集其余部分显着偏差的数据点。它们可能是错误、异…

土壤类型数据

国家地球系统科学数据中心

3、Linux-命令提示符与常用命令(一)

目录 一、命令提示符 二、命令格式 三、常用命令&#xff08;一&#xff09; 0、clear&#xff1a;清空终端窗口的内容。 1、ls&#xff1a;列出当前目录或指定目录下的文件和子目录 2、pwd&#xff1a;显示当前所在工作目录的完整路径。 3、cd&#xff1a;切换目录。 …