知识点动态规划
描述
给定数组arr,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个aim,代表要找的钱数,求组成aim的最少货币数。如果无解,请返回-1.
数据范围:数组大小满足 , 数组中每个数字都满足 ,
要求:时间复杂度 ,空间复杂度 。
示例1
输入:
[5,2,3],20
复制返回值:
4
复制
示例2
输入:
[5,2,3],0
返回值:
0
示例3
输入:
[3,5],2
返回值:
-1
题解
动态规划解法
思路:
- 使用一个数组dp[i]表示要组成i元钱最少需要多少张货币,初始化为-1,表示无解
- 假设输入的数组为m[k],则对于任意的dp[i]要么等于dp[k-m[k]]中有解的那个+1,要么直接就等于1
步骤:
- 申请长度为aim+1的数组dp[i],表示要组成i元钱最少需要的货币数,初始化为-1,根据题意dp[0]应该初始化为0.
- 遍历1到aim,假设索引为i,表示当前要组成的目标,输入货币数组为arr
- 对于任意的货币面值arr[k],如果i - arr[k] == 0,则表示只需要一张,dp[i] = 1
- i-arr[k] < 0,则表示货币面值大于目标,无解,dp[i] = -1
- 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();
}