《程序员代码面试指南--IT名企算法与数据结构题目最优解》 左程云 著

换钱的最少货币数

【题目】

给定数组arr, arr中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,

再给定一个整数aim,代表要找的钱数,求组成aim的最少货币数。

【举例】

arr=[5,2,3],aim=20

4张5元可以组成20元,其他找钱方案都要使用更多的货币,所以返回4.

arr=[5,2,3],aim=0

不用任何货币就可以组成0元,返回0

arr=[3,5],aim=2

根本没法组成2元,钱不能找开的情况下默认返回-1.

/// 方法1:暴力递归求解

#include #include#include#include#include

using namespacestd;#define INT_MAX 1000

int GetMinNum(int A, intB)

{return A > B ?B : A;

}int process(int *arr,int length, int i, intrest);

采用递归的方式实现,时间复杂度很高,不推荐,但是需要理解这里的递归思路int minCoins1(int* arr, int length, intaim)

{if (arr == nullptr || length <= 0 || aim <= 0)

{return -1;

}return process(arr, length, 0, aim);

}//当前考虑的面值是arr[i],还剩rest的钱需要找零//如果返回-1,说明自由使用 arr[i...N-1]面值的情况下,无论如何也无法找零rest//如果返回不是-1,代表自由使用arr[i...N-1]面值的情况下,找零rest需要的最少张数

int process(int *arr, int length, int i, intrest)

{//base case//已经没有面值能够考虑了//如果此时剩余的钱为0,返回0张//如果此时剩余的钱不是0,返回-1

if (i >=length)

{if (rest == 0)

{

cout<< "====================="<

}return rest == 0 ? 0 : -1;

}//最少张数,初始时为-1,因为还没找到有效解

int res = -1;//依次尝试使用当前面值(arr[i])0张、1张、k张,但不能超过rest

for (int k = 0; k*arr[i] <= rest; k++)

{//使用了k张aim[i],剩下的钱为 rest - k*arr[i]//交给剩下的面值去搞定 (arr[i+1...N-1])

int next = process(arr, length, i + 1, rest - k*arr[i]);//说明这个后续过程有效

if (next != -1)

{

res= res == -1 ? next + k : GetMinNum(res, next +k);

}

}

cout<< "res" << res <

}

将递归的思路转为循环。目前不太理解。。  递归转循环!!!

方法2:借用辅助二维数组 dp[N+1][aim+1],通过循环,由下至上,逐层求解。

void printDPArray(int* dp, intcols)

{for (int j = 0; j < cols; j++)

{

printf("%d,", (int)(*(dp +j)));

}

cout<

}int minCoin2(int* arr, int length, intaim)

{if (arr == nullptr || length <= 0 || aim < 0)

{return -1;

}int N =length;int** dp = new int*[N + 1];for (int i = 0; i < N+1; i++)

{

dp[i]= new int[aim + 1];

}for (int i = 0; i < N + 1; i++)

{for (int j = 0; j < aim + 1; j++)

{

dp[i][j]= 0;

}

}//设置最后一排的值,除dp[N][0]为0外,其他都是-1

dp[N][0] = 0;for (int col = 1; col <= aim; col++)

{

dp[N][col]= -1;

}//从底下往上计算每一行

for (int i = N - 1; i >= 0; i--)

{//每一行都从左到右

for (int rest = 0; rest <= aim; rest++)

{

dp[i][rest]= -1;//初始时先设置dp[i][rest]的值无效//下面的值如果有效

if (dp[i + 1][rest] != -1)

{

dp[i][rest]= dp[i + 1][rest];//先设置为下面的值

}//如果左边的位置不越界且有效

if (rest - arr[i] >= 0 && dp[i][rest - arr[i]] != -1)

{//如果之前下面的值无效

if (dp[i][rest] == -1)

{

dp[i][rest]= dp[i][rest - arr[i]] + 1;

}else{//说明下面和左边的值都有效,去最小的

dp[i][rest] = GetMinNum(dp[i][rest], dp[i][rest - arr[i]] + 1);

}

}

}

}二维数组打印,有点不熟悉。。。

for (int i = 0; i < N + 1; i++)

{

printDPArray(*(dp+i),aim + 1);

}

cout<

cout<

cout<< "printDPArray====================start" <

{

printf("Row:%d.", i);for (int j = 0; j < aim + 1; j++)

{

printf("%d,", dp[i][j]);

}

cout<

}

cout<< "printDPArray====================end" <

Row : 0. 0, -1, 1, 1, 2, 1, 2, 2, 2, 3, 2, 3, 3, 3, 4, 3, 4, 4, 4, 5, 4,

Row : 1. 0, -1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7,

Row : 2. 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 6, -1, 7, -1, 8, -1, 9, -1, 10,

Row : 3. 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

printDPArray == == == == == == == == == == end*/

return dp[0][aim];

}

然后逐一扫描钱币,计算每种币种,组成 arr[i] ~ aim 的最少货币数

后面的最优解依靠前面的最优解,所以需要从左往右扫描。

第1行就是 arr[0] 面额的的钱币,依次组成1~aim,需要的张数

方法3:借用一个一维的数组,数组长度是 aim+1。这个比较好理解一些。

void PrintDPArr2(vector&dp)

{for (vector::iterator it1 = dp.begin(); it1 != dp.end(); ++it1)

{

cout<< *it1<

}

cout<

}void MiniCoin3(int* arr, int length, intaim)

{

cout<< "MiniCoin3======================" <

vector dp(aim + 1, INT_MAX);

dp[0] = 0;for (int i = 0; i < length; ++i)

{for (int j = arr[i]; j <= aim; ++j)

{if (dp[j - arr[i]] !=INT_MAX)

{

dp[j]= min(dp[j], dp[j - arr[i]] + 1);

}

}

PrintDPArr2(dp);这里只是打印每行的临时结果,方便后期理解

}if (dp[aim] == INT_MAX) cout << "-1" <

0,1000,1,1000,2,1000,3,

0,1,1,2,2,3,3,

0,1,1,1,2,2,2,

dp[aim] 2*/}

//====================测试用例=================

voidtest1()

{int arrCoin1[3] = {2,1,3};int arrCoin2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 60, 62, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117};//int arrCoin2[] = { 1,3,5,6 };//cout << "Test1================" << endl;//cout << "expected:4. " << minCoin2(arrCoin1, sizeof(arrCoin1) / sizeof(int), 6) << endl;;

MiniCoin3(arrCoin1,sizeof(arrCoin1) / sizeof(int), 6);//MiniCoin3(arrCoin2, sizeof(arrCoin2) / sizeof(int), 122);//cout << "expected:2. " << minCoins1(arrCoin2, sizeof(arrCoin2) / sizeof(int), 122) << endl;;

}intmain()

{

test1();

cout<

system("pause");return 0;

}

最少钱币数不java,【动态规划专题】3:换钱的最少货币数相关推荐

  1. 最少钱币数(动态规划)

    最少钱币数问题也可以看作多重背包问题. 此问题递推公式(也可以叫做动态转移方程):(注:money[i]表示可以使用的纸币的面额组成的数组,dp[m]表示要凑m元至少需要多少张纸币.) dp[m] = ...

  2. java最少钱币数_最少钱币数(凑硬币)详解-2-动态规划算法(初窥)-CCF-CSP练习题(100)...

    目录 这篇使用动态规划算法来解决这个问题,借这篇博客初窥动态规划算法.最少钱币数问题也可以看作多重背包问题. 那么什么是动态规划算法? 动态规划(dynamic programming,DP)是运筹学 ...

  3. java 最少货币单元组合换钱_动态规划. 换钱的最少货币数和最多方法数

    通过对换钱类题目的学习,我们将了解到 暴力递归及优化方法 记忆搜索(优化一) 动态规划的基本实现方法(优化二) 动态规划的空间优化(优化三) 1. 换钱的最少货币数,货币可重复使用 给定数组arr,a ...

  4. [动态规划] 换钱的最少货币数

    算法专题导航页面 [题目描述]     给定数组arr,arr中所有的值都为正整数且不重复.每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个aim,代表要找的钱数,求组成aim的最少 ...

  5. 1003: 最少钱币数

    1003: 最少钱币数 题目描述 作为A公司的职员,最盼望的日子就是每月的8号了,因为这一天是发工资的日子,养家糊口就靠它了.但是对于公司财务处的工作人员来说,这一天则是很忙碌的一天,财务处的小胡最近 ...

  6. 动态规划问题——换钱的最少货币数

    题目: 给定数组arr,arr中所有的值都为正数且不重复.每个值代表一种面值的货币,每种面值的货币可以使用任意张,在给定一个整数aim,代表要找的钱数,求组成aim的最少货币数. 示例: arr = ...

  7. 动态规划-换钱最少货币数

    #encoding:utf-8 _author_ = "Wang Wenchao" #换钱最少的货币数 #给定数组arr,arr中所有的值都为正数且不重复.每个值代表一种面值的货币 ...

  8. ZZULIOJ-1105: 判断友好数对(函数专题)(Java)

    题目描述: 输入两个正整数m和n,顺序输出m到n之间的所有友好数对. 如果两个整数的所有正因子之和(包括1,不包括自身)等于对方,就称这对数是友好的.例如:1184和1210是友好数对,因为 1184 ...

  9. 算法:换钱的最少货币数

    题目 给定数组arr,arr中所有的值都为正整数且不重复.每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个aim,代表要找的钱数,求组成aim的最少货币数. 输入 输入包括两行,第一 ...

最新文章

  1. 值类型与引用类型的区别
  2. CNN中的局部连接(Sparse Connectivity)和权值共享
  3. 【Java】 剑指offer(28) 对称的二叉树
  4. Mybatis DAO开发--Mapper动态代理开发方式
  5. 进程和线程的基本概念
  6. php 配置(转载其他)
  7. Python—进程、线程、协程
  8. C#10,带来了Date和Time类型
  9. 看到一个暴强的翻译,闲的蛋疼,写个c#版的
  10. docker删除所有容器和镜像
  11. 记录——《C Primer Plus (第五版)》第十章编程练习第九题
  12. MySQL8.0.12 EXPLAIN EXTENDED 报错问题
  13. servlet+jsp面试题
  14. python常用英语单词(小白)
  15. 转:普通继电器和自锁继电器的差别
  16. Oracle FND - 用户API fnd_user_pkg的常用用法
  17. iOS动画:3D动画(18)
  18. 有关计算机英语作文素材,英语作文素材范文
  19. HIS(LIS、PACS、RIS、EMR)系统解决方案
  20. 初学python爬虫,记录一下学习过程,requests库模拟登录01

热门文章

  1. 网络编程二-LINUX网络IO模型
  2. 调用微信公众平台API免费给自己发消息
  3. 【MicroPython ESP32】1.8“tft ST7735驱动3Dcube图形显示示例
  4. WEB开启防调试模式
  5. 【雕爷学编程】Arduino动手做(47)---七段LED数码管模块
  6. MATLAB编程实现哈夫曼编码
  7. Shell第三天-讲义
  8. 关于nginx连接被重置引发的网络协议工作解析
  9. centos8部署一个单点ceph
  10. linux系统添加打印机失败,怎么在Linux 系统下安装打印机的驱动 - 驱动管家