前言
还几天没有更新博客,是不是想我了(自恋狂哈哈)。这几天主要是老板让研究pointnet,因为环境配置总是出些问题,(菜鸡一枚)所以耽搁了些时间。搞好了环境,然后看了几天pointnet代码,于是赶快来刷刷题。今天看的仍然是一道动态规划的题目。
题目
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
解析
个人通过刷题,发现了一个小问题,这种求最多最小的一般都可以用动态规划来解题,当然这是特殊情况,具体的还要根据动态规划的定义去判定。这题根据定义来看,确实是动态规划的题。我为了图省事,我通常判别动态规划题一般看问题,要求最少最多八九不离十就是动态规划题,然后看是否有最优子结构,如果有,我就把它当做动态规划来解。
对于动态规划问题,我的解法是把问题设为dp[n],然后去找迭代方程。
此题dp[n]就是金额为n时最少的硬币个数,
n<0,dp[n]=-1;
n=0,dp[n]=0;
n>0,dp[n]=min(dp[n],dp[n-c]+1)
代码
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1,INT_MAX/2);//为什么使用INT_MAX/2,而不是INT_MAX
dp[0]=0;//dp[i]表示总金额为i时,所需的最少硬币个数
//类似于01背包问题
for(auto c:coins)
{
for(int i=c;i<=amount;i++)
{
dp[i]=min(dp[i],dp[i-c]+1);//两种情况,总金额包含c面值和总金额不包含c面值,取其中较小值
}
}
if(dp[amount]==INT_MAX/2)//总金额为amount的dp仍为初始化值,说明没有任何一种硬币组合组成总金额
{
return -1;
}
return dp[amount];
}
};
备注
1.为什么使用INT_MAX/2,而不是INT_MAX
因为如果dp[i-c]为INT_MAX时,加上1就会越界
2.动态规划有个特点就是求最小时,初始化的值一般为不越界的情况尽可能大;求最大时,初始化一般为0;