动态规划专题之Coin Change(leetcode 322)

硬币找零问题,给定一个硬币数组coins和现金amount,要求使用最少的钱币数目凑成amount,如果不能凑成则返回-1。

这题可否使用动态规划呢?

首先,我们需要刻画一个最优解的结构特征。意思就是寻找最优子结构,利用这种子结构从子问题的最优解构造出原问题的最优解。由于我们的amount的一个最优解可以由多个小的amount组成,如果得到了这些小的amount的最优解,那么原问题的最优解就有这些个小问题的最优解组合而成。我们说这个问题满足最优解子结构特征。因此,可以利用动态规划求解。

然后,我们需要递归的定义最优解的值,通常采用bottom-up的方式迭代求解。先求递推关系式:我们用dp[i]描述amount为i时的最优解。那么,如果我们知道了dp[i-1]的值,我们需要知道dp[i]的值,应该怎么求?注意到i为当前现金,此时我们可以选择的面额coins的值必须小于i。那么,我们将原问题分成两种情形考虑:1、选取小于当前现金i的最大的coins值(设为coins[j])。2、不选取coins[j]。

那么如果我们选取了coins[j],我们的最优解应为dp[i-coins[j]]+1。由于dp[m],m<i的值我们都有记录,因此可以得到选择当前的coins[j]的最优解。

如果我们没有选取coins[j],那么我们的最优解仍为dp[i]。

基于两种情形综合考虑,我们的最优解为二者最小值。因此我们的递推关系式为:dp[i] = min(dp[i-coins[j]]+1, dp[i])

在迭代过程中,我们需要对当前的现金i和钱币面额j进行迭代。对于边界条件,设置dp[0]=0,表示在现金为0时,不存在钱币组合。

我们对现金进行迭代,从1到最大值amount,然后对钱币面额数组进行迭代:

 int coinChange(vector<int>& coins, int amount) {
        int len = coins.size();
        vector<int> dp(amount+1, amount+1);
        dp[0] = 0;
        for (int i=1; i<amount+1; i++)
        {
            for (int j=0; j<len; j++)
            {
                 if (i >= coins[j])//现金不变,面额变,更新当前现金所使用的面额的数目。注意到对于m<i的dp[m]可以直接得到。
                 {
                     dp[i] = min(dp[i-coins[j]]+1, dp[i]);    //取最小的数目,可以重复使用面额
                 }
            }
           
        }
        return dp[amount] > amount ? -1:dp[amount];//如果amount没发生改变,说明无法组合成现金
    }


猜你喜欢

转载自blog.csdn.net/u012260341/article/details/79855894