[Leetcode] 322 & 518. Coin Change 1 & 2

Coin Change 1

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.

这道题目是一个很典型的dp问题,如果想要知道amount的最小数量,其实就是看max(上一个不选当前硬币面值的最小数量, 选择当前硬币面值+之前的剩余的最小数量)

转化成状态方程就是f[i] = max(f[i], f[i - last_coin] + 1). 注意这里有一些小的技巧:因为每个硬币的面值都是int(整数)且大于0(否则没有意义),所以可以最大组成的

amount一定是amount(所有都为1元),那么可以设置最大值为amount + 1,这个值是永远无法触碰到的上界。最后只需要比较f[amount] > amount就可以判断否有解。

接下来要做的事情就是罗列所有的可能:

1. 不同面值对应当前amount

2. 不同amount对应当前的面值

在罗列第二个情况的时候需要保证当前的amount-当前选中的硬币的面值的>0,所以我在第二个循环的时候j是从coins[i]开始,这样j - coins[i] >= 0

同时还有一个细节:在设置f的长度的时候要设置成amount + 1,因为这里是1 indexed(index对应的即选择的amount,而不是amount - 1)。

解法1:

 1 #define vi vector<int>
 2 class Solution {
 3 public:
 4     int coinChange(vi& coins, int amount) {
 5         vi f(amount, amount + 1);
 6         int n = coins.size();
 7         f[0] = 0;
 8         for (int i = 0; i < n; ++i) 
 9             for (int j = coins[i]; j <= amount; ++j)
10                 f[j] = min(f[j], f[j - coins[i]] + 1);
11         return f[amount] > amount ? -1 : f[amount];
12     }
13 };

Coin Change 2

You are given coins of different denominations and a total amount of money. Write a function to compute the number of combinations that make up that amount. You may assume that you have infinite number of each kind of coin.

Example 1:

Input: amount = 5, coins = [1, 2, 5]
Output: 4
Explanation: there are four ways to make up the amount:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

Example 2:

Input: amount = 3, coins = [2]
Output: 0
Explanation: the amount of 3 cannot be made up just with coins of 2.

Example 3:

Input: amount = 10, coins = [10] 
Output: 1

Note:

You can assume that

  • 0 <= amount <= 5000
  • 1 <= coin <= 5000
  • the number of coins is less than 500
  • the answer is guaranteed to fit into signed 32-bit integer

题目理解:与第一题不同的是这里需要求出所有的方案数,而不是最小的方案。那么很自然就会想到把状态f[i]改成为当前amount = i的时候的所有组成方案。

那么状态方程便是:组成当前amount的所有方案数 += 之前不选当前硬币面值的方案数

这里的起始值是1,代表的是在amount为0的情况下,有且只有一种方案数(不取也是一种方案)

解法1:

 1 #define vi vector<int>
 2 class Solution {
 3 public:
 4     int change(int amount, vi& coins) {
 5         vi f(amount + 1, 0);
 6         f[0] = 1;
 7         int n = coins.size();
 8         for (int i = 0; i < n; ++i)
 9             for (int j = coins[i]; j <= amount; ++j)
10                 f[j] += f[j - coins[i]];
11         return f[amount];
12     }
13 };

猜你喜欢

转载自www.cnblogs.com/goldenticket/p/11909320.html