[DP]换钱的方法数
题目三
给定数组arr, arr中所有的值都为整数且不重复.每个值代表一种面值的货币,每种面值的货币可以使用任意张,在给定一个整数aim代表要找的钱数,求换钱有多少种方法.
解法一 --暴力递归
用0张arr[0], 让arr[1...N-1]组成剩下的钱,这样的方法数记为res1
用1张arr[0], 让arr[1...N-1]组成剩下的钱(aim - arr[0]),方法数记为res2
用2张arr[0], 让arr[1...N-1]组成剩下的钱(aim - 2 * arr[0]),方法数记为res3
...
从上面可以看出,这是一个递归的过程,总的方法书为res1 + res2 +...
代码一
int process1(vector<int> arr, int index, int aim) {
int res = 0;
if (index == int(arr.size()))
res = aim == 0 ? 1 : 0;
else {
for (int k = 0; k * arr[index] <= aim; k ++) //k代表使用arr[index]的张数
res += process1(arr, index + 1, aim - k * arr[index]);
}
return res;
}
// 暴力递归的方法
int coins1(vector<int> arr, int aim) {
if (arr.size() == 0 || aim < 0)
return 0;
return process1(arr, 0, aim);
}
方法二--记忆化搜索
递归多次调用函数自己,会消耗大量的栈空间.递归的一个初级的优化方法就是用一张表记忆已经计算出的结果,避免重复计算.这张表的维度需要分析递归过程中那些是变量.从上面的代码中可以看到arr是不变的,只有index和aim在递归中是变化的,可以做出相应维度的map表来表示递归的过程.代码如下:
代码
int process2(vector<int> arr, int index, vector<vector<int> > &mapTable, int aim) {
int res = 0;
if (index == int(arr.size()))
res = aim == 0? 1:0;
else {
//mapTable 中的特殊值,0说明mapTable[i][j]没有被计算过,-1表示计算过,但是返回值为0
int mapValue = 0;
for (int k = 0; k * arr[index] <= aim; k ++) {
mapValue = mapTable[index + 1][aim - k * arr[index]];
if (mapValue != 0)
res += mapValue == -1 ? 0 : mapValue;
else
res += process2(arr, index + 1, mapTable, aim - arr[index] * k);
}
mapTable[index][aim] = res == 0 ? -1 : res;
}
return res;
}
//记忆化搜索方法
int coins2(vector<int> arr, int aim) {
if (arr.size() == 0 || aim < 0)
return 0;
//记忆搜索表,用于保存递归的中间结果,避免重复计算
vector<vector<int> > mapTable(arr.size() + 1, vector<int>(aim + 1));
return process2(arr, 0, mapTable, aim);
}
方法三--动态规划
可以直接参考代码,时间复杂度为O(N * aim^2)
代码
// 动态规划的方法
int coins3(vector<int> arr, int aim) {
int length = arr.size();
if (length == 0 || aim < 0)
return 0;
vector<vector<int> > dp(length, vector<int>(aim + 1));
for (int k = 0; k * arr[0] <= aim ; k ++) // 初始化第一行
dp[0][k * arr[0]] = 1;
for (int i = 1; i < length; i ++) // 初始化第一列,0张a[i]可以构成0元钱也是一种方法
dp[i][0] = 1;
int sum;
for (int i = 1; i < length; i ++) {
for (int j = 1; j <= aim; j ++) {
sum = 0;
for (int k = 0; k * arr[i] <= j; k++)
sum += dp[i - 1][j - k * arr[i]];
dp[i][j] = sum;
}
}
return dp[length - 1][aim];
}
动态规划--优化
一
上面的DP代码最内层的for循环是根据递归中的步骤来表达的.步骤一的方法数为dp[i-1][j],而第二种到第k种情况的方法数累加值其实就是dp[i][j-arr[i]]的值.所以递推方程为:
dp[i][j] = dp[i-1][j] + dp[i][j-arr[i]]
这样时间复杂度就简化成了O(N*aim),
二
还有进一步的优化就是空间,上面的动态规划空间复杂度都是O(N*aim),通过把二维的dp数组用一维数组来代替,滚动计算能够是空间复杂度降低到O(aim)
[DP]换钱的方法数的更多相关文章
- 算法进阶面试题07——求子数组的最大异或和(前缀树)、换钱的方法数(递归改dp最全套路解说)、纸牌博弈、机器人行走问题
主要讲第五课的内容前缀树应用和第六课内容暴力递归改动态规划的最全步骤 第一题 给定一个数组,求子数组的最大异或和. 一个数组的异或和为,数组中所有的数异或起来的结果. 简单的前缀树应用 暴力方法: 先 ...
- [程序员代码面试指南]递归和动态规划-换钱的方法数(DP,完全背包)
题目描述 给定arr,arr中所有的值都为正数且不重复.每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim,求组成aim的方法数. 解题思路 完全背包 和"求换钱的 ...
- 算法之Python实现 - 003 : 换钱的方法数
[题目]给定数组arr,arr中所有的值都为正数且不重复.每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数,求组成aim的方法数. [代码1]递归 impor ...
- 2017 Wuhan University Programming Contest (Online Round) B Color 树形dp求染色方法数
/** 题目:Color 链接:https://oj.ejq.me/problem/23 题意:给定一颗树,将树上的点最多染成m种颜色,有些节点不可以染成某些颜色.相邻节点颜色不同.求染色方法数. 思 ...
- [程序员代码面试指南]递归和动态规划-机器人达到指定位置方法数(一维DP待做)(DP)
题目描述 一行N个位置1到N,机器人初始位置M,机器人可以往左/右走(只能在位置范围内),规定机器人必须走K步,最终到位置P.输入这四个参数,输出机器人可以走的方法数. 解题思路 DP 方法一:时间复 ...
- 数字和为sum的方法数
[编程题] 数字和为sum的方法数 给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数. 当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案. 输入描 ...
- 一个n*n 的方格,要从左上角走到右下角,一次只能往右或往下走一步,求算法得出所有走动的方法数。
题目一:一个n*n 的方格,要从左上角走到右下角,一次只能往右或往下走一步,求算法得出所有走动的方法数. 分析:对于第(i,j)个格子,只有向右走一步到达或者向左走一步到达,dp(i,j) = d(i ...
- [Android] Android统计Apk , jar包方法数
reference to : http://www.jianshu.com/p/61e8f803e0d1 Android在开发过程中,随着引用的库以及业务的增多,不可避免的会出现64K limit问题 ...
- POJ 3463 有向图求次短路的长度及其方法数
题目大意: 希望求出走出最短路的方法总数,如果次短路只比最短路小1,那也是可取的 输出总的方法数 这里n个点,每个点有最短和次短两种长度 这里采取的是dijkstra的思想,相当于我们可以不断找到更新 ...
随机推荐
- 【游记】NOIP2019初赛
声明 我的游记是一个完整的体系,如果没有阅读过往届文章,阅读可能会受到障碍. ~~~上一篇游记的传送门~~~ 前言 (编辑中) 文章推荐:[游记]NOIP2019复赛
- 用 bat 文件实现 excel 周报复制
又要写周报???? 写周报就算了每次都要改这一大堆的日期,什么鬼嘛,最骚的我还总是有的忘记改.... 作为一个正儿八经的程序员,固定每周某天干重复的一件事,哦~~ 这是机器人 程序应 ...
- maven3实战之仓库
maven3实战之仓库(maven仓库分类) maven3实战之仓库(maven仓库分类) ---------- 对于maven来说,仓库只分为两类:本地仓库和远程仓库.当maven根据坐标寻找构件的 ...
- android ——网络编程
一.WebView 这个View就是一个浏览器,用于展示网页的. 布局文件: <LinearLayout xmlns:android="http://schemas.android.c ...
- 减谈迷宫C++
今天老师让做了个迷宫问题,我一看到就发现和我之前写过的一个程序是一样 的,但是在后来编写的时候有一个地方搞错了,最后下课了我还是没有正确的编写好,然后今天回来之后自己有看了一下,现在已经解决了. #i ...
- 大白话5分钟带你走进人工智能-第32节集成学习之最通俗理解XGBoost原理和过程
目录 1.回顾: 1.1 有监督学习中的相关概念 1.2 回归树概念 1.3 树的优点 2.怎么训练模型: 2.1 案例引入 2.2 XGBoost目标函数求解 3.XGBoost中正则项的显式表达 ...
- 记一次解决tomcat自动关闭的bug
最近一个运行了4年的javaee web项目,经常接到客户反馈系统无法打开.登录服务器查看服务,发现是tomcat自动关闭了.基本是3到4天发生一次. 运维人员开始以为是其他服务杀死了tomcat服务 ...
- 如何彻底禁用 werfalut.exe
在程序中调用 控制台程序 的时候,一旦出现控制台出现 crash 往往会弹出 werfault 窗口, 这样往往会锁死线程,导致程序无法继续运行. 那如何禁止 werfault 窗口的弹出呢? 在 s ...
- Spring Cloud与Dubbo的完美融合之手「Spring Cloud Alibaba」
很早以前,在刚开始搞Spring Cloud基础教程的时候,写过这样一篇文章:<微服务架构的基础框架选择:Spring Cloud还是Dubbo?>,可能不少读者也都看过.之后也就一直有关 ...
- Java - 手动解析不带引号的JSON字符串
目录 1 需求说明 2 解析代码 2.1 实现思路 2.2 详细代码 2.3 测试样例 1 需求说明 项目中遇到了一批不带引号的类JSON格式的字符串: {Name:Heal,Age:20,Tag:[ ...