动态规划之兑换零钱

209 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 28 天,点击查看活动详情

在牛客上有这样一个题。

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

本题其实很像背包,他也是背包问题的一种简化版本

image.png

他在限定金额内,保证使用张数最少。而动态规划思想是把复制问题变成简单小问题,对子问题处理得到目标数的结果。

所以我们需要考虑怎么划分。

直接解法--》暴力递归

最容易想到是把数组排序,每次尽量拿最大值的面额,剩下的再依次选择。如果剩下的不能满足,就最大面额少拿一张,继续递归。

但是我们知道递归容易超时,使用想到了动态规划方式

假设我们用dp【i】表示,凑齐i元钱需要的最小货币数。那么我们可以知道,i最小为1,最大为aim。当i=0时候,我们不需要选择货币就可以得到,所以结果为0。

假设在1~aim之间,目标值=aim-当前值dp[i]=min(dp[i],dp[目标值]+1).

即转移方程里面,dp[i]=不使用当前数量和使用当前数量,得到的最小值

代码如下: image.png

和他类似的还有一个给出面值数组arr,其中的值都是正数且无重复。每个值都认为是一种面值,并且张数是无限的,现给出正数aim,求返回组成aim的方法数。

两个其实都是类似的问题, 需要几种方法

解法1,暴力递归。

我们知道,从左到右变量,当指向数组最后一个数时候,如果aim等于0,表示已经有一种解法,如果aim!=0,表示无解。

然后对张数进行循环,条件是当前值 *张数< aim

image.png

修改成动态规划的时候,dp数组是二维的,行表示货币种类,列表示目标货币值

image.png