Week9

Week9

Dynamic Programming
question source: Coin Change

question description

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

Example 1:
Input: coins = [1, 2, 5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1

Example 2:
Input: coins = [2], amount = 3
Output: -1

Note:
You may assume that you have an infinite number of each kind of coin.

这是一道标签为动态规划的题。这两周学习了动态规划的内容,以及相关经典问题的讨论。说实话,这部分内容比较难想,但一旦想出来,实现就比较简单。老师上课的时候老说,其实不难,照着书本上和老师的分析来想,自然是不难,但是要自己想呢,还是要多做题才有感觉。现在来看这道题,是说给你一个数目,把它分成若干个硬币的组合,求这个组合的最小数目,如果不能拆分,就返回-1。

解决方法

这实际上是背包问题的变种,背包问题在上课时有讨论过。用动态规划的思想来解决问题。动态规划是一种非常强大的计算模式,其解决问题的方式是首先定义它的一组子问题,然后按照由小到大,以小问题的解答支持大问题求解的模式,依次解决所有子问题,并最终得到原问题(最大的子问题)的求解。
我们要用一种途径来缩小原来的问题,这里自然想到用较小的金额。
定义 k ( m ) = m k(m) = 金额为m分解的最小硬币个数。
那么对于某些i,就存在 K ( m ) = k ( m m i ) K(m) = k(m - m_i)
这个i,必须要使得k(m)最小。因为我们不知道究竟是哪个i,所以要尝试所有的可能。因此,
K ( m ) = min i : m i < = m { k ( m m i ) + 1 } K(m) = \min_{i: m_i <= m} \lbrace k(m - m_i) + 1 \rbrace

然后就要定义最小的子问题了。K(0)肯定是0咯。先默认k(m)为-1,表示不能拆分,然后看 k ( m m i ) k(m - m_i) 是不是也是-1,如果对于全部的i都是,则说明k(m)不能拆分,设为-1,否则就更新为最小的。
然后就从左到右填写一个长度为amount + 1的一维表格,总的计算时间为O(n * amount)。

实现代码如下

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int num[amount + 1];
        num[0] = 0;
        for(int i = 1; i <= amount; i++){
            int minum = -1;
            for(int j = 0; j < coins.size(); j++){
                int kid = i - coins[j];
                if(kid >= 0){
                    if(num[kid] != -1){
                        if(minum == -1){
                            minum = num[kid] + 1;
                        }else{
                            minum = std::min(minum, num[kid] + 1);
                        }
                    }
                }
            }
            num[i] = minum;
        }
        return num[amount];
    }
};

运行的效果还行。动态规划真的很简单高效,只要有一个公式定义原问题与子问题的关系,就很容易实现,很好用。问题就是有的问题没这么容易想。

猜你喜欢

转载自blog.csdn.net/pjsfirstlaw/article/details/83629042