代码随想录刷题笔记 Day 51 | 单词拆分 No.139 | 多重背包理论基础

文章目录

    • Day 51
      • 01. 单词拆分(No. 139)
        • <1> 题目
        • <2> 笔记
        • <3> 代码
      • 02. 多重背包理论基础
        • 2.1 解题思路
        • 2.2 携带矿石资源(卡码网No.56)
          • <1> 题目
          • <2> 笔记
          • <3> 代码

Day 51

01. 单词拆分(No. 139)

题目链接

代码随想录题解

<1> 题目

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true

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

示例 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

<2> 笔记

给定一个字符串,问这个字符串能不能拆分成字典中的元素;反过来看就是字典中的字符串能不能填满这个字符串。而且字典中的字符是可以 无限次 使用的,这其实就类似一个 完全 背包问题;构建一个 01背包问题和构建一个完全背包问题的递推公式的最大区别其实就是,能不能在取得这个物品的状态的基础上再次取得物品

先来看题目中有什么状态,以及这个状态能否被转移:题目中问的是能否利用字典中的内容来构成这个字符串,对于一个字符串,划分其状态最好的方式其实就是其 长度,如果知道其中的 一段 是可以由字典中的内容来组成的,那这个状态能否可以转移呢?

如果这个遍历到的部分前面是可以拆分成字典中的内容,并且 这样一段中还是字典中的内容的话,那这一段加上前一段就是可以被拆分成字典中的内容了,这样状态就得到了转移。

那这样 dp 数组的含义也确定了,即从 index = 0index = i 能否拆分成字典中的单词。

再来考虑初始化,毫无疑问 dp[0] 是要初始化为 true 的,否则遍历是没有意义的。

首先来遍历字符串的长度

for (int i = 0; i < dp.length; i++) {}

再去确定 dp[i] 是否符合要求,这时候需要一个变量从头开始遍历,来检测某一段是否为 true

for (int j = 0; j < i && !dp[i]; j++) {
    if (dp[j]) {}
}

但这样是不够的,还需要从 ji 的这一段也是字典中的单词,即要添上另一个条件:

if (dp[j] && wordDict.contains(s.substring(j, i))) {
	dp[i] = true;
}

这样其实就写出了递推公式。

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

02. 多重背包理论基础

2.1 解题思路

与01背包和完全背包不同的是,多重背包会规定每个物品 各有多少个,而不是简单的一个或者无数个。

但是解决多重背包问题的思路也很简单,我只需要将这每个物品 看成多个重量和价值都相同的物品即可,这样就可以通过处理01背包的思路来决解决这个问题了,但这种解法是最优的嘛?这里先按下不表,先来看一个例题。

2.2 携带矿石资源(卡码网No.56)
<1> 题目

题目链接

代码随想录题解

题目描述

你是一名宇航员,即将前往一个遥远的行星。在这个行星上,有许多不同类型的矿石资源,每种矿石都有不同的重要性和价值。你需要选择哪些矿石带回地球,但你的宇航舱有一定的容量限制。

给定一个宇航舱,最大容量为 C。现在有 N 种不同类型的矿石,每种矿石有一个重量 w[i],一个价值 v[i],以及最多 k[i] 个可用。不同类型的矿石在地球上的市场价值不同。你需要计算如何在不超过宇航舱容量的情况下,最大化你所能获取的总价值。

输入描述

输入共包括四行,第一行包含两个整数 C 和 N,分别表示宇航舱的容量和矿石的种类数量。
接下来的三行,每行包含 N 个正整数。具体如下:
第二行包含 N 个整数,表示 N 种矿石的重量。
第三行包含 N 个整数,表示 N 种矿石的价格。
第四行包含 N 个整数,表示 N 种矿石的可用数量上限。

输出描述

输出一个整数,代表获取的最大价值。

输入示例

10 3
1 3 4
15 20 30
2 3 2

输出示例

90

提示信息
数据范围:
1 <= C <= 10000;
1 <= N <= 10000;
1 <= w[i], v[i], k[i] <= 10000;

<2> 笔记

和上面说的一样,本题是一个多重背包问题,题目输入中可以形成三个数组,首先是和前面相同的 weightvalue 数组,还有每个物品的个数,number 数组。

首先想到的解题思路就是把所有重复的物品都当作单独的物品去处理,即第 i 个物品要遍历 number[i] 次,这才算遍历完了本次的物品,一共有 weight.length 个物品,每个物品有 number[i] 个,又要内层遍历背包,所以一共需要三层 for 循环,写出代码是这样的:

for (int i = 0; i < N; i++) { // 遍历矿石
    for (int j = 1; j <= number[i]; j++) { // 遍历矿石的数量
        for (int k = dp.length - 1; k >= weight[i]; k--) { // 遍历背包
            dp[k] = Math.max(dp[k], dp[k - weight[i]] + value[i]);
        }  
    }
}

但是提交之后会发现超时(大悲)

为什么会超时呢?试想一下,如果第一个物品有十个,那就遍历十次,没啥问题,那如果有一百个,一千个,一万个呢?那真的要遍历这么多次吗?

先来看一个例子,比如说容量为 5,有 1 种矿石,重量为 2,价值为 3,共有 10 个,即输入是:

5 1 2 3 10

查看输出的结果:

0 0 3 3 3 3 
0 0 3 3 6 6 
0 0 3 3 6 6 
0 0 3 3 6 6 
0 0 3 3 6 6 
0 0 3 3 6 6 
0 0 3 3 6 6 
0 0 3 3 6 6 
0 0 3 3 6 6 
0 0 3 3 6 6 

其实从第三行开始就没有什么区别了,这是为什么呢?物品价值为 2,第三行就是尝试将 3 个物品放入背包中,但是背包的总容量为 5,所以后面的遍历其实是没有意义的。

这样其实就知道,对于一个物品只需要遍历 k * weight[i] <= 背包容量 的部分就可以了,因为后面的部分和这些是完全一样的,基于这个思路再来改造一下代码。

for(int i = 0; i < N; i++) { // 遍历物品
    for(int j = dp.length - 1; j >= weight[i]; j--) { // 遍历背包容量
    	for (int k = 1; k <= number[i] && (j - k * weight[i]) >= 0; k++) { 
    		dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);
        }
    }
}

这次提交上去就不会报错了。

<3> 代码
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int C = sc.nextInt(); // 宇航舱的最大容量
        int N = sc.nextInt(); // 矿石的种类
        int[] weight = new int[N];
        int[] value = new int[N];
        int[] number = new int[N];
        int[] dp = new int[C + 1];
        int totalNum = 0; 
        for (int i = 0; i < N; i++) weight[i] = sc.nextInt();
        for (int i = 0; i < N; i++) value[i] = sc.nextInt();
        for (int i = 0; i < N; i++) number[i] = sc.nextInt();
        for (int i = 0; i < N; i++) {
            for (int j = C; j >= weight[i]; j--) {
                for (int k = 1; k <= number[i] && (j - k * weight[i]) >= 0; k++) { // 遍历背包
                    dp[j] = Math.max(dp[j], dp[j - k * weight[i]] + k * value[i]);
                }  
            }
        }
        System.out.println(dp[C]);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python·算法·每日一题(3月15日)合并两个有序链表

题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]示例 2&#xff1a; 输入&#xff1a;l1 [], l2 [] 输出&am…

如何正确地设置Outlook SMTP发送电子邮件?

Outlook SMTP发送邮件配置方法&#xff1f;Outlook怎么开启SMTP&#xff1f; 在使用Outlook发送邮件时&#xff0c;正确设置SMTP服务器是确保邮件能够顺利发送的关键步骤。接下来&#xff0c;就让AokSend一起探讨如何正确地设置Outlook SMTP发送电子邮件吧&#xff01; Outlo…

【Redis】Redis常用命令之Hash

1.hset&#xff1a;设置hash中指定的字段&#xff08;field&#xff09;的值&#xff08;value&#xff09;。 HSET key field value [field value ...]时间复杂度&#xff1a;插⼊⼀组field为O(1),插⼊N组field为O(N)。 返回值&#xff1a;添加的字段的个数。 2.hget&#xf…

vscode 导入前端项目

vscode 导入前端项目 导入安装依赖 运行 参考vscode 下载 导入 安装依赖 运行 在前端项目的终端中输入npm run serve

【洛谷 P8637】[蓝桥杯 2016 省 B] 交换瓶子 题解(贪心算法)

[蓝桥杯 2016 省 B] 交换瓶子 题目描述 有 N N N 个瓶子&#xff0c;编号 1 ∼ N 1 \sim N 1∼N&#xff0c;放在架子上。 比如有 5 5 5 个瓶子&#xff1a; 2 , 1 , 3 , 5 , 4 2,1,3,5,4 2,1,3,5,4 要求每次拿起 2 2 2 个瓶子&#xff0c;交换它们的位置。 经过若干次…

Springboot的配置文件及其优先级

配置文件 内置配置文件 配置文件的作用&#xff1a;修改SpringBoot自动配置的默认值&#xff1b;SpringBoot在底层都给我们自动配置好&#xff1b;SpringBoot使用一个全局的配置文件&#xff0c;配置文件名是固定的&#xff1a; application.propertiesapplication.yml 以上…

【无标题】vmprotect net 混淆效果挺不错

vmprotect net 混淆效果挺不错,测试了一个&#xff0c;以前的写程序。用dnspy测试一下&#xff0c;效果非常好。 sunnf0451qq.com

string接口[小白理解篇]

作文目的 本文是为了加深对string底层函数的一点理解(请勿与底层源码混为一谈)&#xff0c;下面从模拟与注意项出发。 一.string 功能化模拟 1.迭代器模拟 迭代器&#xff0c;为实现简单便理解故使用指针的方式(非说明迭代器使用该方法实现)。其中的begin、end都是为了给迭代…

【论文笔记合集】ARIMA 非平稳过程通过差分转化为平稳过程

本文作者&#xff1a; slience_me 文章目录 ARIMA 非平稳过程通过差分转化为平稳过程文章原文具体解释详解参照 ARIMA 非平稳过程通过差分转化为平稳过程 文章原文 Many time series forecasting methods start from the classic tools [38, 10]. ARIMA [7, 6] tackles the fo…

爬虫入门到精通_框架篇16(Scrapy框架基本使用)_名人名言的抓取

1 目标站点分析 抓取网站&#xff1a;http://quotes.toscrape.com/ 主要显示了一些名人名言&#xff0c;以及作者、标签等等信息&#xff1a; 点击next&#xff0c;page变为2&#xff1a; 2 流程框架 抓取第一页&#xff1a;请求第一页的URL并得到源代码&#xff0c;进行下…

避免阻塞主线程 —— Web Worker 示例项目

前期回顾 迄今为止易用 —— 的 “盲水印“ 实现方案-CSDN博客https://blog.csdn.net/m0_57904695/article/details/136720192?spm1001.2014.3001.5501 目录 CSDN 彩色之外 &#x1f4dd; 前言 &#x1f6a9; 技术栈 &#x1f6e0;️ 功能 &#x1f916; 如何运行 ♻️ …

Linux 部署 Samba 服务

一、Ubuntu 部署 Samba 1、安装 Samba # 更新本地软件包列表 sudo apt update# 安装Samba sudo apt install samba# 查看版本 smbd --version2、创建共享文件夹&#xff0c;并配置 Samba 创建需要共享的文件夹&#xff0c;并赋予权限&#xff1a; sudo mkdir /home/test sud…

深度学习PyTorch 之 LSTM-中文多分类

LSTM 代码流程与RNN代码基本一致&#xff0c;只是这里做了几点优化 1、数据准备 数据从导入到分词&#xff0c;流程是一致的 # 加载数据 file_path ./data/news.csv data pd.read_csv(file_path)# 显示数据的前几行 data.head()# 划分数据集 X_train, X_test, y_train, y_…

【UE5】非持枪趴姿移动混合空间

项目资源文末百度网盘自取 创建角色在非持枪状态趴姿移动的动画混合空间 在BlendSpace文件夹中单击右键选择 动画(Animation) 中的混合空间(Blend Space) 选择SK_Female_Skeleton 命名为BS_NormaProne 打开BS_NormaProne 水平轴表示角色的方向&#xff0c;命名为Directi…

Vue2 父子组件某一属性的双向绑定

原本&#xff1a;父组件使用props传值给孩子组件初始化&#xff0c;触发事件子组件使用$emit传值给父组件&#xff0c;很麻烦后来&#xff1a;使用computed和$event例子代码&#xff1a; <template><div class"box">grandpa <el-input v-model"…

pta—剪切粘贴

使用计算机进行文本编辑时常见的功能是剪切功能&#xff08;快捷键&#xff1a;Ctrl X&#xff09;。请实现一个简单的具有剪切和粘贴功能的文本编辑工具。 工具需要完成一系列剪切后粘贴的操作&#xff0c;每次操作分为两步&#xff1a; 剪切&#xff1a;给定需操作的起始位置…

《深入解析 C#》—— C# 2 部分

文章目录 第二章 C# 22.1 泛型&#xff08;*&#xff09;2.2 default 和 typeof&#xff08;*&#xff09;2.3 可空值类型2.3.1 Nullable<T> 结构体&#xff08;framework 支持&#xff09;2.3.2 装箱&#xff08;CLR 支持&#xff09;2.3.3 “?”后缀&#xff08;语法支…

蓝桥杯(1):python排序

1 基础 1.1 输出 1.1.1 去掉输出的空格 print("Hello","World",123,sep"") print("hello",world,123,sep) print(hello,world,123) #输出结果 #HelloWorld123 #helloworld123 #hello world 123 1.1.2 以不同的方式结尾 print(&quo…

【Android】AOSP 架构

Android 官网对 AOSP 结构图进行了更新&#xff0c;如下所示&#xff1a; Android 应用&#xff08;Android Apps&#xff09; 完全使用 Android API 开发的应用。在某些情况下&#xff0c;设备制造商可能希望预安装 Android 应用以支持设备的核心功能。 特权应用&#xff08…

先验分布、后验分布、极大似然的一点思考

今天和组里同事聊天的时候&#xff0c;无意中提到了贝叶斯统计里先验分布、后验分布、以及极大似然估计这三个概念。同事专门研究如何利用条件概率做系统辨识的&#xff0c;给我画了一幅图印象非常深刻&#xff1a; 其中k表示时序关系。上面这个图表示后验分布是由先验分布与似…