Open azl397985856 opened 2 years ago
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount+1];
dp[0] = 1;
for (int j = 0; j < coins.length; j++) {
for (int i = 1; i <= amount; i++) {
if (i - coins[j] >= 0) dp[i] += dp[i - coins[j]];
}
}
return dp[amount];
}
}
class Solution {
public int change(int cnt, int[] cs) {
int n = cs.length;
int[][] f = new int[n + 1][cnt + 1];
f[0][0] = 1;
for (int i = 1; i <= n; i++) {
int val = cs[i - 1];
for (int j = 0; j <= cnt; j++) {
f[i][j] = f[i - 1][j];
for (int k = 1; k val <= j; k++) {
f[i][j] += f[i - 1][j - k val];
}
}
}
return f[n][cnt];
}
}
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] = dp[i] + dp[i - coin];
}
}
return dp[amount];
}
}
学习官方题解
var change = function(amount, coins) {
const dp = new Array(amount + 1).fill(0);
dp[0] = 1;
for (const coin of coins) {
for (let i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
};
思路:
对于求极值问题,主要考虑动态规划 Dynamic Programming 来做,好处是保留了一些中间状态的计算值,可以避免大量的重复计算。
动态规划 (iterate coins), dp[i] 表示组成钱数i的不同组合数 dp[i] = dp[i] + dp[i - coin], 对于一种硬币,由两个状态: 使用或不使用,
使用则组合方法 dp[i] = dp[i] 则对于钱数i的总的组合方法= dp[i] + dp[i - coins[i]]
复杂度分析:
代码(C++):
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1, 0);
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; ++i){
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
};
class Solution {
public int change(int amount, int[] coins) {
int[][] dp =new int[coins.length + 1][amount + 1];
for (int[] ints : dp) {
ints[0] = 1;
}
for (int i = 1; i < coins.length + 1; i++) {
int coin = coins[i - 1];
for (int j = 1; j < amount + 1; j++) {
if(j >= coin) {
dp[i][j] = dp[i][j - coin] + dp[i - 1][j];
}else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[coins.length][amount];
}
}
class Solution {
public int change(int amount, int[] coins) {
int[] dp =new int[amount + 1];
dp[0] = 1;
for (int i = 1; i < coins.length + 1; i++) {
int coin = coins[i - 1];
for (int j = 1; j < amount + 1; j++) {
if(j >= coin) {
dp[j] = dp[j - coin] + dp[j];
}
}
}
return dp[amount];
}
}
DP
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
# dp[i] 达到某一和的所有组合数
dp = [0] * (amount + 1)
# dp[i] = dp[i - coin] 的和
dp[0] = 1
for coin in coins:
for i in range(1, amount + 1):
diff = i - coin
if diff >= 0:
dp[i] += dp[diff]
return dp[amount]
时间复杂度: O(n amount) 空间复杂度:O(n amount)
完全背包问题
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount+1];
dp[0] = 1;
for(int i = 1 ; i <= coins.length ; i++){
int val = coins[i-1];
for(int j = val ; j <= amount; j++){
dp[j] += dp[j-val];
}
}
return dp[amount];
}
}
时间复杂度:O(m*n) 空间复杂度:O(m)
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
}
var change = function (amount, coins) {
const dp = new Array(amount + 1).fill(0);
dp[0] = 1;
for (const coin of coins) {
for (let i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
};
var change = function(amount, coins) {
const dp = new Array(amount + 1).fill(0)
dp[0] = 1
for (let j = 0; j < coins.length; j++) {
for (let i = coins[j]; i <= amount; i++) {
dp[i] += dp[i - coins[j]]
}
}
return dp[amount]
};
空间:O(n) n为coins的长度 时间:O(n * amount)
思路: transition function is dp[i][j] = dp[i-1][j] + dp[i][j-nums[i-1]]
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount+1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
}
Time Complexity: O(n * amount), n is the length of coins array Space Complexity: O(amount)
完全背包问题,本题求的是组合数,所以外层loop coins,内层loop amount,保证每个组合就被添加一次
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1, 0);
dp[0] = 1;
for (int i = 0; i < coins.size(); i++) {
for (int j = 0; j <= amount; j++) {
// coins[i] > j : 不拿 dp[i][j] = dp[i - 1][j]
// coins[i] <= j :可拿可不拿 dp[i - 1][j] + dp[i][j - coin[i]]
if (coins[i] <= j) {
dp[j] += dp[j - coins[i]];
}
}
}
return dp[amount];
}
};
class Solution {
public:
int change(int amount, vector
}
};
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
}
时间:O(N*amount)
空间:O(amount)
和爬楼梯的解法类似。
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0]*(amount+1)
dp[0] = 1
for coin in coins:
for j in range(coin,amount+1):
dp[j] = dp[j-coin]+dp[j]
return dp[amount]
复杂度分析
思路:定义状态 dp[i] [j] 为前i个硬币组成金额为j的组合,由于后一个的状态依赖于前一个状态,采用滚动数组进行空间优化。
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0]*(amount+1)
dp[0] = 1
for num in coins:
for j in range(num,amount+1):
dp[j] += dp[j-num] #状态转移方程
return dp[-1]
复杂度分析:
时间复杂度:(num*amount)
空间复杂度:O( amount)
const change = (amount, coins) => {
let dp = Array(amount + 1).fill(0);
dp[0] = 1;
for (let i = 0; i < coins.length; i++) {
for (let j = coins[i]; j <= amount; j++) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
};
title: "Day 64 518. 零钱兑换 II" date: 2021-11-12T16:56:19+08:00 tags: ["Leetcode", "c++", "NP"] categories: ["91-day-algorithm"] draft: true
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
示例 1:
输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
示例 2:
输入:amount = 3, coins = [2]
输出:0
解释:只用面额 2 的硬币不能凑成总金额 3 。
示例 3:
输入:amount = 10, coins = [10]
输出:1
提示:
1 <= coins.length <= 300
1 <= coins[i] <= 5000
coins 中的所有值 互不相同
0 <= amount <= 5000
- 1、与昨天的题目不同的是,本次的硬币的数据规模变小了,而且coins中的所有值互不相同,所以本次题目用模板解决问题会更加简单。
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1);
dp[0] = 1;
for(auto& n : coins)
{
for (int i = n; i <= amount; i++) {
dp[i] += dp[i - n];
}
}
return dp[amount];
}
};
时间复杂度:O(n ^ 2)
空间复杂度:O(n)
https://leetcode-cn.com/problems/coin-change-2/
DFS,DP
# 1d DP
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
n = len(coins)
dp = [0 for _ in range(amount + 1)]
dp[0] = 1
for i in range(1, n + 1):
coin = coins[i - 1]
for j in range(0, amount + 1):
if (j >= coin):
dp[j] += dp[j - coin]
return dp[amount]
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp=[0]*(amount+1)
dp[0]=1
for coin in coins:
for current_amount in range(1,amount+1):
if current_amount-coin>=0:
dp[current_amount]+=dp[current_amount-coin]
return dp[amount]
Time: O(m*n)
Space: O(n) n is the number of amount
dp
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins:
for x in range(coin, amount + 1):
dp[x] += dp[x - coin]
return dp[amount]
动态规划。
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins:
for i in range(coin, amount + 1):
dp[i] += dp[i - coin]
return dp[amount]
时间:O(amount * len(coins)) 空间:O(amount)
https://leetcode.com/problems/coin-change-2/
dp[i]
means the number of combination of coins to form total i
. So the problem is converted to find the dp[amount]dp[i] = sum(dp[i - coin[j])
where coin[j] <= i. Because based on dp[i - coin[j]], we only need to add one coin[j] to it, then we get the total i. So all the dp[i - coin[j]] form the dp[i], as long as coin[j] <= i.class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
// this way to embed the loop causes duplicate combination
// i.e. amount = 3, coins[1, 2]
// combination (1, 2) and (2, 1) will becount seperately, but they are duplicate
// for(int i = 1; i <= amount; i++){
// for(int coin: coins){
// if(coin <= i){
// dp[i] += dp[i - coin];
// }
// }
// }
// this way to embed the loop guarantees each type of coin will be iterated only once
// for each amount, each coin will be considered only once in order
for(int coin: coins){
for(int i = coin; i <= amount; i++){
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
}
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins:
for i in range(1, amount + 1):
if coin <= i:
dp[i] += dp[i - coin]
return dp[amount]
class 零钱兑换II_518 {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for(int i = 0; i< coins.length; i++) {
for(int j = 1; j< amount + 1; j++) {
if(j >= coins[i])
dp[j] += dp[j - coins[i]]; // 二维省略成一维 dp[i][j] 表示 前i个硬币中 组成j有多少种组合 dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i]] // 顺理成章去掉第一维
}
}
return dp[amount];
}
}
class 零钱兑换II_518 {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for(int i = 0; i< coins.length; i++) {
for(int j = 1; j< amount + 1; j++) {
if(j >= coins[i])
dp[j] += dp[j - coins[i]]; // 二维省略成一维 dp[i][j] 表示 前i个硬币中 组成j有多少种组合 dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i]] // 顺理成章去掉第一维
}
}
return dp[amount];
}
}
动态规划
int coinChangeII(vector<int> coins, int amount) {
vector<priority_queue<int>> dp[amount + 1];
for (int i = *min_element(coins.begin(), coins.end()); i <= amount; ++i) {
if (find(coins.begin(), coins.end(), i) != coins.end()) {
priority_queue<int> q;
q.push(i);
dp[i].push_back(q);
}
for (auto &v : coins) {
int idx = i - v;
if (idx > 0 && !dp[idx].empty()) {
for (auto &vs : dp[idx]) {
priority_queue<int> tmp = vs;
tmp.push(v);
dp[i].push_back(tmp);
}
}
}
}
dp[amount].erase(unique(dp[amount].begin(), dp[amount].end()), dp[amount].end());
return dp[amount].size();
}
func change(amount int, coins []int) int {
dp := make([]int, amount + 1)
dp[0] = 1
for _, coin := range coins {
for i := 0; i + coin <= amount; i++{
dp[i+coin] += dp[i];
}
}
return dp[amount]
}
class Solution {
public int change(int amount, int[] coins) {
int[] f = new int[amount + 1];
f[0] = 1; //f[0][0] = 1;
for(int i = 1; i <= coins.length; i++)
{
int v =coins[i - 1];
for(int j = v; j <= amount; j++)
f[j] += f[j - v];
}
return f[amount];
}
}
时间:O(amount * len(coins)) 空间:O(amount)
dp[i] = 所有dp[i-coin]的可能性之和,遍历所有coin
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount+1, 0);
dp[0] = 1;
for(auto& coin:coins)
{
for(int i=coin;i<=amount; i++)
{
dp[i] += dp[i-coin];
}
}
return dp[amount];
}
};
Space:O(n^2) Time:O(n^2)
完全背包的组合问题。dp[i][j]表示容量为j的背包装前i个硬币有几种方式。
题目含义算是比较容易抽象成背包问题的题目
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount+1)
dp[0] = 1
for coin in coins:
for i in range(coin, amount+1):
dp[i] += dp[i-coin]
return dp[-1]
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
}
时间复杂度:O(n^2) 空间复杂度:O(n)
javascript
/*
* @lc app=leetcode.cn id=518 lang=javascript
*
* [518] 零钱兑换 II
*/
// @lc code=start
/**
* @param {number[]} coins
* @param {number} amount
* @return {number}
*/
var coinChange = function(coins, amount) {
const dp = Array.from({ length: amount + 1 }).fill(0)
dp[0] = 1
for (let coin of coins) {
for (let i = coin; i <= amount; i++) {
dp[i] += dp[i - coin]
}
}
return dp[amount]
};
// @lc code=end
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
n = len(coins)
dp = [0] * (amount + 1)
dp[0] = 1
for i in range(1, n + 1):
coin = coins[i - 1]
for j in range(coin, amount + 1, 1):
dp[j] = dp[j - coin] + dp[j]
return dp[amount]
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int x = coin; x <= amount;x++) {
dp[x] += dp[x - coin];
}
}
return dp[amount];
}
}
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int i = 0; i < coins.length; i++) {
for (int j = coins[i]; j <= amount; j++) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
}
/**
* @param {number} amount
* @param {number[]} coins
* @return {number}
*/
var change = function(amount, coins) {
let dp = new Array(amount + 1).fill(0);
dp[0] = 1;
for(let i of coins) {
for(let j = i; j <= amount; j++) {
dp[j] = dp[j - i] + dp[j]
}
}
return dp[amount]
};
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1);
dp[0] = 1;
for (int& coin : coins) {
for (int i = coin; i <= amount; ++i) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
class Solution { public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for(int i = 0; i< coins.length; i++) {
for(int j = 1; j< amount + 1; j++) {
if(j >= coins[i])
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
}
完全背包问题
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0 for _ in range(amount + 1)]
dp[0] = 1
for coin in coins:
for a in range(coin, amount + 1):
dp[a] += dp[a - coin]
return dp[amount]
class Solution(object):
def change(self, amount, coins):
"""
:type amount: int
:type coins: List[int]
:rtype: int
"""
dp =[0]*(amount+1)
dp[0] = 1
for i in range(len(coins)):
for j in range(1,amount+1):
if j >= coins[i]:
dp[j] += dp[j-coins[i]]
return dp[-1]
时间复杂度:O(mn) 空间复杂度:O(1)
背包问题,动态规划
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
}
时间复杂度:O(n^2)
complete backpack problem
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
# numbers of combination
# fix the amount and scan the coins
dp = [0]*(amount+1)
dp[0] = 1
# if amount < min(coins):
# return 0
for i in range(len(coins)):
for j in range(1, amount+1):
if j >= coins[i]:
dp[j] += dp[j - coins[i]]
return dp[-1]
背包
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1); // dp[i]: 凑成金额 i 的组合方式的总数量
dp[0] = 1; // 可以使用一个tets case测试出来
for (int& coin : coins)
{
for (int i = coin; i <= amount; i++)
{
dp[i] = dp[i - coin] + dp[i]; /* 当前面值的硬币, 如果选它接下来处理总金额 i-coin, 如果不选它继续处理总金额i */
}
}
return dp[amount];
}
};
时间复杂度:O(MN)
空间复杂度:O(M)
class Solution {
public:
int change(int amount, vector
}
return dp[amount];
}
}
动态规划
var change = function(amount, coins) {
const dp = new Array(amount + 1).fill(0);
dp[0] = 1;
for (const coin of coins) {
for (let i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/coin-change-2/solution/ling-qian-dui-huan-ii-by-leetcode-soluti-f7uh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
动态规划
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins:
for x in range(coin, amount + 1):
dp[x] += dp[x - coin]
return dp[-1]
定义状态 dp[i][j] 为使用前 i 个硬币组成金额 j 的组合数
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins:
for i in range(coin, amount + 1):
dp[i] += dp[i-coin]
return dp[amount]
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
n = len(coins)
dp = [0] * (amount + 1)
dp[0] = 1
for i in range(1, n + 1):
coin = coins[i - 1]
for j in range(coin, amount + 1, 1):
dp[j] = dp[j - coin] + dp[j]
return dp[amount]
518. 零钱兑换 II
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/coin-change-2/
前置知识
暂无
题目描述
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
示例 1: