代码随想录算法训练营第四十四天|完全背包、LeetCode518 零钱兑换、LeetCode 377组合总和IV

news/2024/7/24 4:48:56 标签: 算法, leetcode, 数据结构

完全背包

思路:相比于0-1背包,完全背包中的物品是可以重复使用的,在代码上,背包的循环是从前往后的。在面对常规求完全背包最大价值的问题中,物品的循环和背包的循环的顺序是可以变换的,一般是先遍历物品再遍历背包。在考虑组合排列问题时,如果考虑组合问题,先遍历物品再遍历背包,如果考虑排列问题,先遍历背包,后遍历物品。

518.零钱兑换

思路:这道题跟之前01背包一道题的递归函数相同,首先确定dp数组及其下标的含义,dp[j]代表装满容量为j的背包最多有dp[j]中方法。递推公式为dp[j]+=dp[j-coins[i]],很容易理解,装满j容量的背包的方法数为装满j-coins[i]容量的方法数的和,因为装满j-coins[i]容量的方法数,只需要再加上个coins[i]就是容量j,因此对所有j-coins[i]容量的方法数求和即为dp[j]。初始化dp数组,求方法数的问题,初始化dp[0]=1,当背包容量为0时,什么也不装,也是一种方法,如果dp[0]初始化为0了,后续的递推都为0。遍历顺序,由于是完全背包问题,因此在遍历背包时从前到后,物品可以重复利用,因为是组合问题,因此先遍历物品再遍历背包。打印dp数组,可以用于debug。

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        //确定dp数组及其下标含义 dp[j]代表装满容量j的背包的方法数
        //递推公式dp[j]+=dp[j-cions[i]];
        //初始化dp数组 dp[0]=1; 装满容量为0的背包的方法数为1,如果为0后续递推所有都为0;
        //遍历顺序,由于物品可以重复使用,正向遍历
        //打印dp数组,可以用于debug
        vector<int> dp(amount+1,0);
        dp[0]=1;
        for(int i = 0;i<coins.size();i++)// 先遍历物品再遍历背包是组合问题, 因为在每个物品的循环里都是先放coins[1]在考虑放coins[2],即可能会出现{1,1,2}的情况,但绝不会出现{1,2,1}的情况。
        //先遍历背包再遍历物品是排列问题,因为dp[j]是基于dp[j-coins[i]]来计算的,dp[j-coins[i]]中可能包含了{1,2}但在dp[j]的循环中,又可能会加入了{1}出现{1,2,1}的情况
        {
            for(int j = coins[i];j<=amount;j++)
            {
                dp[j]+=dp[j-coins[i]];
            }
        }
        return dp[amount];
    }
};

377.组合总和IV

思路:该问题中顺序不同的序列被视作不同的组合,其实就是排列问题。也是求方法数,因此与上一题不同的地方就是遍历顺序,需要先遍历背包,再遍历物品数。第一遍跑代码的时候int溢出了,dp[target]之前的索引有溢出的数值,因此在if判断中加了 dp[j]<=INT_MAX-dp[j-nums[i]],可以解决溢出问题。

class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        //确定dp数组及其下标含义 dp[j]为装满背包容量j的方法数。
        //递推公式 dp[j] +=dp[j-nums[i]];
        //初始化dp数组 dp[0]=1;
        //遍历顺序,由于顺序不同的序列被视作不同的组合,因此这道题是求排列数,应先遍历背包后遍历物品,从前往后遍历
        //打印dp数组,可以用于debug
        vector<int> dp(target+1,0);
        dp[0]=1;
        for(int j = 0;j<=target;j++)
        {
            for(int i =0;i<nums.size();i++)
            {
                if(j>=nums[i]&&dp[j]<=INT_MAX-dp[j-nums[i]])
                {
                    dp[j]+=dp[j-nums[i]];
                }
            }
        }
        return dp[target];
    }
};

收获:

完全背包与01背包的区别在于物品能否重复使用,代码上的区别在于遍历背包时,从前往后还是从后往前。

组合问题与排列问题的区别在于{1,2,1}与{1,1,2}算不算同一种方法,如果是同一种方法,是组合问题,先遍历物品再遍历背包,如果不是同一种方法,是排列问题,先遍历背包,再遍历物品。


http://www.niftyadmin.cn/n/5423676.html

相关文章

安装 Oracle Database 23c Free

安装 Oracle Database 23c Free 0. 引言1. 事情准备2. 开始安装3. 配置4. 设置 Bash 环境5. 创建 tablespace 和 user6. 分配 memory 给 in-memory vector index7. 重启启动后,手动启动数据库8. 重启启动后,手动启动Listener9. 手动启动Pluggable Database10. 自动启动Plugga…

请列出50个java热点面试题目

以下是50个Java热点面试题目&#xff0c;涵盖了Java基础知识、集合框架、多线程、JVM、设计模式等多个方面&#xff1a; Java的基本数据类型有哪些&#xff1f;它们各自的特点是什么&#xff1f;谈谈Java中的自动装箱和拆箱机制。Java中的字符串是不可变的&#xff0c;谈谈你对…

HTML 学习笔记(十一)表单

一、分块 1.单行文本框控件–文本框和密码框 文本框控件通过单标签input实现&#xff0c;其具有必要属性type来控制输入控件的类型(默认为text即文本信息)&#xff0c;密码框的type为password(口令)。   表单的动作属性定义了目的文件的文件名。由动作属性定义的这个文件通常…

1.什么是ClickHouse?

什么是ClickHouse&#xff1f; ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。 在传统的行式数据库系统中&#xff0c;数据按如下顺序存储&#xff1a; RowWatchIDJavaEnableTitleGoodEventEventTime#0893543506621Investor Relations12016-05-18 05:19:2…

vue 下载的插件从哪里上传?npm发布插件详细记录

文章参考&#xff1a; 参考文章一&#xff1a; 封装vue插件并发布到npm详细步骤_vue-cli 封装插件-CSDN博客 参考文章二&#xff1a; npm发布vue插件步骤、组件、package、adduser、publish、getElementsByClassName、important、export、default、target、dest_export default…

Python基础语法:基本数据类型(列表)

现实世界中总是存在一组一组的事物。"组"的概念作为基本数据类型的一种&#xff0c;它也是来源于我们去解决现实生活中的一些问题而产生的。它需要有“组”这样的一个数据类型来丰富我们的基本数据类型。 那么在Python中如何来表示“组”的概念呢&#xff1f; 在Py…

Vscode g++ cmake 学习笔记

1 Linux常用指令 2开发环境搭建 3GCC编译器 4th gdb 调试器 5vscode 6cmake

【FFmpeg】ffmpeg 命令行参数 ⑤ ( 使用 ffmpeg 命令提取 音视频 数据 | 保留封装格式 | 保留编码格式 | 重新编码 )

文章目录 一、使用 ffmpeg 命令提取 音视频 数据1、提取音频数据 - 保留封装格式2、提取视频数据 - 保留封装格式3、提取视频数据 - 保留编码格式4、提取视频数据 - 重新编码5、提取音频数据 - 保留编码格式6、提取音频数据 - 重新编码 一、使用 ffmpeg 命令提取 音视频 数据 1…