​BM70 兑换零钱(一)​

知识点​动态规划​

描述

给定数组arr,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个aim,代表要找的钱数,求组成aim的最少货币数。如果无解,请返回-1.

数据范围:数组大小满足 [典型-动态规划]BM70 兑换零钱(一)-中等_多条件动态规划 , 数组中每个数字都满足 [典型-动态规划]BM70 兑换零钱(一)-中等_动态规划_02[典型-动态规划]BM70 兑换零钱(一)-中等_动态规划_03

要求:时间复杂度 [典型-动态规划]BM70 兑换零钱(一)-中等_多条件动态规划_04 ,空间复杂度 [典型-动态规划]BM70 兑换零钱(一)-中等_动态规划_05

示例1

输入:

[5,2,3],20

复制返回值:

4

复制

示例2

输入:

[5,2,3],0

返回值:

0


示例3

输入:

[3,5],2

返回值:

-1

题解

动态规划解法

思路:

  1. 使用一个数组dp[i]表示要组成i元钱最少需要多少张货币,初始化为-1,表示无解
  2. 假设输入的数组为m[k],则对于任意的dp[i]要么等于dp[k-m[k]]中有解的那个+1,要么直接就等于1

步骤:

  1. 申请长度为aim+1的数组dp[i],表示要组成i元钱最少需要的货币数,初始化为-1,根据题意dp[0]应该初始化为0.
  2. 遍历1到aim,假设索引为i,表示当前要组成的目标,输入货币数组为arr
  1. 对于任意的货币面值arr[k],如果i - arr[k] == 0,则表示只需要一张,dp[i] = 1
  2. i-arr[k] < 0,则表示货币面值大于目标,无解,dp[i] = -1
  3. i-arr[k] > 0,只需要查看dp[i-arr[k]]是否有解,如果有解则dp[i] = min(dp[i-arr[k]]+1,dp[i]),否则为-1

代码如下:

int minMoney(vector<int> &arr, int aim)
{
if (aim == 0)
{
return 0;
}
std::vector<int> dp(aim + 1, -1);
std::sort(arr.begin(), arr.end());
for (int i = 1; i < dp.size(); ++i)
{
for (int k = 0; k < arr.size(); ++k)
{
int target = i - arr[k]; // i 表示的是aim,arr[k]表示从arr中任取一个面值的money
if (target < 0) // 如果target小于0,表示这个面值arr[k]超过了i,无解
{
break;
}
else if (target == 0)
{
dp[i] = 1;
continue;
}
else if (dp[target] == -1)
{
continue;
}

// 可能有解的情况
if (dp[i] == -1)
{
dp[i] = dp[target] + 1;
}
else
{
dp[i] = std::min(dp[target] + 1, dp[i]);
}
}
}
return dp.back();
}