利用动态规划(DP)解决 Coin Change 问题

问题来源

这是Hackerrank上的一个比较有意思的问题,详见下面的链接:
https://www.hackerrank.com/challenges/ctci-coin-change

问题简述

给定m个不同面额的硬币,C={c0, c1, c2…cm-1},找到共有几种不同的组合可以使得数额为n的钱换成等额的硬币(每种硬币可以重复使用)。
比如:给定m=3,C={2,1,3},n=4,那么共有4种不同的组合可以换算硬币

  1. {1,1,1,1}
  2. {1,1,2}
  3. {2,2}
  4. {1,3}

解决方案

基本思路是从硬币(coins)的角度出发,考虑coins[0]仅使用1次的情况下有几种组合,coins[0]仅使用2次的情况下有几种组合,依次类推,直到 (n - coins[0] * 使用次数) < 0 则终止,而每个 (n - coins[0]) 下又可以递归 (n - coins[0] - coins[1]) 的情况,直到考虑完所有的硬币。
这样说可能还是没有说清楚,下面以m=3,C={1,2,3},n=4为例,用图来说明一下(建议结合程序一起看)。
coinChange递归图

图1:coin Change不完整递归图
上图没有画出完整的递归过程(有点麻烦~偷了个懒),不过把能得出结果的几条路径都描绘出来了。其中,recursion(money, index)中,money指的是还没有进行兑换的钱,index指的是要用哪个coin去兑换,比如这里的0指的是coins[0]=1,1指的是coins[1]=2,2指的是coins[2]=3,3是不存在的,这也是程序的终止条件之一。 注意到再递归的过程中有重叠子问题(我用紫色标注出了其中一个),这就可以用动态规划的思想来解决了,创建一块空间来存储已经算过的结果就可以了。 # 程序代码 好了,下面直接上程序了,结合图看好理解~
#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>using namespace std;long long recursion(vector<int> &coins, int money, int index, unordered_map<string, int> &memo){//终止条件2个if (0 == money)return 1;if (index >= coins.size() || money < 0)return 0;string key = to_string(money) + " , " + to_string(index);//如果记录中有的话就直接返回就好了if (memo.find(key) != memo.end())return memo[key];long long res = 0;int remaining = money;while(remaining >= 0){res += recursion(coins, remaining, index + 1, memo);remaining -= coins[index];}//记录一下memo[key] = res;return res;
}long long make_change(vector<int> coins, int money) {//用哈希表来记录 <剩下的钱-用的硬币>:换硬币的组合数unordered_map<string, int> memo;long long res = recursion(coins, money, 0, memo);return res;
}int main(){int n;int m;cin >> n >> m;vector<int> coins(m);for(int coins_i = 0;coins_i < m;coins_i++){cin >> coins[coins_i];}cout << make_change(coins, n) << endl;return 0;
}

Sample Input

10 4
2 5 3 6

Sample Output

5

真正的DP

上面的那段代码是以自顶向下的方式来解决问题的,思路比较清晰,而真正的动态规划是自底向上的,思路其实也差不多,下面给出代码~

long long make_change(vector<int> coins, int money) {vector<long long> memo(money + 1, 0);memo[0] = 1;for (int i = 0; i < coins.size(); i++){for (int j = coins[i]; j <= money; j++){memo[j] += memo[j - coins[i]];}}return memo[money];
}

补充——硬币不能重复使用

如果每种硬币不能重复使用的话,又该怎么办呢?这只需要再程序上做一些小的改动就可以了,真的是非常神奇~
要细细体会一下~

long long make_change(vector<int> coins, int money) {vector<long long> memo(money + 1, 0);memo[0] = 1;for (int i = 0; i < coins.size(); i++){//改动处:由从前往后改成了从后往前,略去了重复的情况for (int j = money; j >= coins[i]; j--){memo[j] += memo[j - coins[i]];}}return memo[money];
}

补充2——不同顺序表示不同组合

然后再来变一变,如果每种硬币可以使用无限多次,但是不同的顺序表示不同的组合,那么又有多少种组合呢?
比如:

coins = [1, 2, 3]
money = 4可能的组合情况有:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)注意,不同的顺序序列表示不同的组合~所以结果是7。

这种情况下的代码是:

long long make_change(vector<int> coins, int money) {vector<long long> memo(money + 1, 0);memo[0] = 1;//改变了里外循环的顺序for (int i = 1; i <=money; i++){for (int j = 0; j < coins.size(); j++){if (i - coins[j] >= 0)memo[i] += memo[i - coins[j]];}}return memo[money];
}

要仔细体会一下三种情况下的区别和代码微妙的变化~

结束语

动态规划的代码量其实不大,但是思维量还是挺大的,要写正确还是要折腾挺久的~
本人是初学者,如有错误,还请指正~

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

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

相关文章

jquery datatable设置垂直滚动后,表头(th)错位问题

jquery datatable设置垂直滚动后&#xff0c;表头(th)错位问题 问题描述&#xff1a; 我在datatable里设置&#xff1a;”scrollY”: ‘300px’,垂直滚动属性后&#xff0c;表头的宽度就会错位&#xff0c;代码如下&#xff1a; <!-- HTML代码 --> <table id"dem…

三、解决ie缓存问题

解决 IE 缓存问题 问题&#xff1a;在一些浏览器中(IE),由于缓存机制的存在&#xff0c;ajax 只会发送的第一次请求&#xff0c;剩余多次请求不会在发送给浏览器而是直接加载缓存中的数据。 在谷歌浏览器中&#xff0c;修改了服务器代码&#xff0c;重新发送请求时&#xff0…

imageNamed和imageWithContentsOfFile-无法加载图片的问题

问题描述 图片资源放在Assets.xcassets中&#xff0c;分别用UIImage的类方法imageNamed和imageWithContentsOfFile获取图片对象&#xff0c;但发生奇怪的情况&#xff0c;前者获取到图片对象&#xff0c;后者结果为nil。代码如下&#xff1a; 1.通过UIImage的类方法imageNamed:…

LeetCode 309: 一个很清晰的DP解题思路

问题来源 题目来源链接见下方&#xff1a; https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/ 问题简述&#xff1a; 假如有一个 i 个元素的数组&#xff0c;数组的每个元素表示了第 i 天某只股票的价格&#xff0c;设计一种算法来…

五、手动取消ajax请求 解决重复发送请求问题

server.js: // 1. 引入express const express require(express)// 2. 创建应用对象 const app express()// 3. 创建路由规则 app.get(/server, (request, response) > {// 设置响应头 设置允许跨域response.setHeader(Access-Control-Allow-Origin, *)// 设置响应体respo…

linux ps命令详解

ps命令用于监测进程的工作情况。进程是正在运行的程序&#xff0c;一直处于动态变化中&#xff0c;而ps命令所显示的进程工作状态时瞬间的。 使用方式&#xff1a;ps[options][-help] 常用参数&#xff1a; -A &#xff1a;显示所有进程 -a&#xff1a;显示一个终端的所有进程。…

用多元线性回归预测网页访问量(R语言)

前言 该问题来源于《机器学习:实用案例解析》中的第5章。在书中&#xff0c;已经对该问题给出了一种解决方案&#xff0c;但是我觉得写的还是太简略了一些&#xff0c;没有把考虑问题的整个思路给写出来&#xff0c;所以&#xff0c;在这里给出我的一些想法。 问题简述 我们…

六、jQuery 中的 AJAX 跨域问题

第 2 章&#xff1a;jQuery 中的 AJAX 官方中文文档&#xff1a;https://jquery.cuishifeng.cn/jQuery.Ajax.html 2.1 get 请求 $.get(url, [data], [callback], [type]) url:请求的 URL 地址。data:请求携带的参数。callback:载入成功时回调函数。type:设置返回内容格式&a…

常用的几种编程语言的介绍

编程语言&#xff08;programming language&#xff09;&#xff0c;来自百度百科的解释为&#xff1a;编程语言是用来定义计算机程序的形式语言。它是一种被标准化的交流技巧&#xff0c;用来向计算机发出指令。一种计算机语言让程序员能够准确地定义计算机所需要使用的数据&a…

三门问题(Monty Hall problem)背后的贝叶斯理论

文章目录1 前言2 问题简介3 直观的解释4 贝叶斯理论的解释1 前言 三门问题可以说有着各种版本的解释&#xff0c;但我看了几个版本&#xff0c;觉得没有把其中的条件说清楚&#xff0c;所以还是决定按照自己的理解记录一下这个特别有意思的问题。 2 问题简介 三门问题&#…

一、在vue项目中使用mock.js(详解)

步骤1.搭建测试项目 步骤1.1创建项目 命令&#xff1a; vue create mock-demo 步骤1.2安装依赖 命令&#xff1a; #使用axios发送ajax cnpm install axios--save #使用mockjs产生随机数据 cnpm install mockjs--save-dev #使用json5解决ison文件&#xff0c;无法添加注释…

二、在jQuery中使用mockjs

在jQuery项目中使用mock.js 步骤1.搭建项目 步骤1.1创建项目 新建文件夹jquery-mock-demo 步骤1.2新建index.html&#xff0c;引入jquery.js文件和mock.js <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title&g…

Android 中如何计算 App 的启动时间?

&#xff08;转载&#xff09; 已知的两种方法貌似可以获取&#xff0c;但是感觉结果不准确&#xff1a;一种是&#xff0c;adb shell am start -w packagename/activity,这个可以得到两个值&#xff0c;ThisTime和TotalTime&#xff0c;不知道两个有什么区别&#xff0c;而且与…

项目实战:Express实现学生管理系统(CRUD)

一、起步 初始化 npm init -y 生成package.json文件 模板处理 cnpm install express --save cnpm install bootstrap --savenpm install --save art-template npm install --save express-art-template//两个一起安装 npm i --save art-template express-art-template文件目录…

2016年度 JavaScript 展望(下)

【编者按】本文作者为资深 Web 开发者 TJ VanToll, TJ 专注于移动端 Web 应用及其性能&#xff0c;是《jQuery UI 实践》 一书的作者。 本文系 OneAPM 工程师编译呈现&#xff0c;以下为正文的第二部分。点此阅读第一部分。 本地移动 apps 在2015年&#xff0c;出现了一种新的基…

Python模块之MyQR——制作个性化动态二维码(超详细)

一、首先安装MyQR 第一种方式&#xff1a;cmd 命令行输入 pip install MyQR 第二种方式&#xff1a;pyCharm中手动选择进行安装 二、 myqr.run() 函数里面的参数 三、编写代码 # encodingutf-8 from MyQR import myqrmyqr.run(words"https://blog.csdn.net/weixin_448…

地址选择控件开发-

先睹为快 闲话少说&#xff0c;我们先来看看今天我们研究的控件的最终效果图(参照天猫的送货地址设置的效果)&#xff1a; “地址选择Web控件”的基本组成&#xff1a; 使用控件举例&#xff1a; <!--需要加载和引用的文件--> <link rel"stylesheet" href&q…

逻辑回归(logistic regression)的本质——极大似然估计

文章目录1 前言2 什么是逻辑回归3 逻辑回归的代价函数4 利用梯度下降法求参数5 结束语6 参考文献1 前言 逻辑回归是分类当中极为常用的手段&#xff0c;因此&#xff0c;掌握其内在原理是非常必要的。我会争取在本文中尽可能简明地展现逻辑回归(logistic regression)的整个推导…

使用mongoose 在 Node中操作MongoDB数据库

MongoDB 关系型和非关系型数据库 关系型数据库&#xff08;表就是关系&#xff0c;或者说表与表之间存在关系&#xff09;。 所有的关系型数据库都需要通过sql语言来操作所有的关系型数据库在操作之前都需要设计表结构而且数据表还支持约束 唯一的主键默认值非空 非关系型…