Coin Change II
Coin Change II: Counting Distinct Combinations
- This problem involves finding the number of distinct combinations of coins that sum up to a given target amount.
- It is a classic example of a Dynamic Programming (DP) problem, focusing on combinations rather than permutations.
Problem Description : Coin Change ||
You are given:
- An integer array coins where each element represents the denomination of a coin (e.g., 1, 5, 10, etc.).
- An integer amount representing the target sum.
Objective: Return the number of distinct combinations of coins that sum up to amount. If it’s impossible to reach the amount, return 0.
Problem Breakdown
- Input: 2D grid of non-negative integers.
- Objective: Find the length of the longest strictly increasing path.
- Movement: Can move to adjacent cells (up, down, left, right) but not diagonally.
- Constraints: Each move must go to a cell with a strictly greater value.
- Goal: Determine the longest path by efficiently exploring the grid.
Explanation:
- 1+1+1+1 = 4
- 1+1+2 = 4
- 2+2 = 4
- 1+3 = 4
Example 2
Input: amount = 7, coins = [2,4]
Output: 0
Constraints:
- 1 <= coins[i] <= 1000
- 1 <= coins.length <= 100
- 0 <= amount <= 1000
There are mainly three approach to solve this problem –
- Recursion
- Dynamic Programming (Top-Down)
- Dynamic Programming (Bottom-up)
1. Recursion
Python
C++
Java
JavaScript
Python
class Solution: def change(self, amount: int, coins: List[int]) -> int: coins.sort() memo = [[-1] * (amount + 1) for _ in range(len(coins) + 1)] def dfs(i, a): if a == 0: return 1 if i >= len(coins): return 0 if memo[i][a] != -1: return memo[i][a] res = 0 if a >= coins[i]: res = dfs(i + 1, a) res += dfs(i, a - coins[i]) memo[i][a] = res return res return dfs(0, amount)
C++
class Solution { public: int change(int amount, vector& coins) { sort(coins.begin(), coins.end()); return dfs(coins, 0, amount); } private: int dfs(const vector & coins, int i, int a) { if (a == 0) { return 1; } if (i >= coins.size()) { return 0; } int res = 0; if (a >= coins[i]) { res = dfs(coins, i + 1, a); res += dfs(coins, i, a - coins[i]); } return res; } };
Java
public class Solution { public int change(int amount, int[] coins) { Arrays.sort(coins); return dfs(coins, 0, amount); } private int dfs(int[] coins, int i, int a) { if (a == 0) { return 1; } if (i >= coins.length) { return 0; } int res = 0; if (a >= coins[i]) { res = dfs(coins, i + 1, a); res += dfs(coins, i, a - coins[i]); } return res; } }
JavaScript
class Solution { /** * @param {number} amount * @param {number[]} coins * @return {number} */ change(amount, coins) { coins.sort((a, b) => a - b); const dfs = (i, a) => { if (a === 0) return 1; if (i >= coins.length) return 0; let res = 0; if (a >= coins[i]) { res = dfs(i + 1, a); res += dfs(i, a - coins[i]); } return res; }; return dfs(0, amount); } }
2. Dynamic Programming (Top-Down)
Time & Space Complexity
- Time complexity: O(n^3)
- Space complexity: O(n^2)
Python
Java
C++
JavaScript
Python
class Solution: def longestIncreasingPath(self, matrix: List[List[int]]) -> int: ROWS, COLS = len(matrix), len(matrix[0]) dp = {} # (r, c) -> LIP def dfs(r, c, prevVal): if (r < 0 or r == ROWS or c < 0 or c == COLS or matrix[r][c] <= prevVal ): return 0 if (r, c) in dp: return dp[(r, c)] res = 1 res = max(res, 1 + dfs(r + 1, c, matrix[r][c])) res = max(res, 1 + dfs(r - 1, c, matrix[r][c])) res = max(res, 1 + dfs(r, c + 1, matrix[r][c])) res = max(res, 1 + dfs(r, c - 1, matrix[r][c])) dp[(r, c)] = res return res for r in range(ROWS): for c in range(COLS): dfs(r, c, -1) return max(dp.values())
Java
public class Solution { public int change(int amount, int[] coins) { Arrays.sort(coins); int[][] memo = new int[coins.length + 1][amount + 1]; for (int[] row : memo) { Arrays.fill(row, -1); } return dfs(0, amount, coins, memo); } private int dfs(int i, int a, int[] coins, int[][] memo) { if (a == 0) return 1; if (i >= coins.length) return 0; if (memo[i][a] != -1) return memo[i][a]; int res = 0; if (a >= coins[i]) { res = dfs(i + 1, a, coins, memo); res += dfs(i, a - coins[i], coins, memo); } memo[i][a] = res; return res; } }
C++
class Solution { public: int change(int amount, vector& coins) { sort(coins.begin(), coins.end()); vector > memo(coins.size() + 1, vector (amount + 1, -1)); return dfs(0, amount, coins, memo); } int dfs(int i, int a, vector & coins, vector >& memo) { if (a == 0) return 1; if (i >= coins.size()) return 0; if (memo[i][a] != -1) return memo[i][a]; int res = 0; if (a >= coins[i]) { res = dfs(i + 1, a, coins, memo); res += dfs(i, a - coins[i], coins, memo); } memo[i][a] = res; return res; } };
JavaScript
class Solution { /** * @param {number} amount * @param {number[]} coins * @return {number} */ change(amount, coins) { coins.sort((a, b) => a - b); let memo = Array.from({ length: coins.length + 1 }, () => Array(amount + 1).fill(-1)); const dfs = (i, a) => { if (a === 0) return 1; if (i >= coins.length) return 0; if (memo[i][a] !== -1) return memo[i][a]; let res = 0; if (a >= coins[i]) { res = dfs(i + 1, a); res += dfs(i, a - coins[i]); } memo[i][a] = res; return res; }; return dfs(0, amount); } }
3. Dynamic Programming (Bottom-Up)
Time & Space Complexity
- Time complexity: O(m∗n)
- Space complexity: O(m∗n)
Python
Java
C++
JavaScript
Python
class Solution: def change(self, amount: int, coins: List[int]) -> int: n = len(coins) coins.sort() dp = [[0] * (amount + 1) for _ in range(n + 1)] for i in range(n + 1): dp[i][0] = 1 for i in range(n - 1, -1, -1): for a in range(amount + 1): if a >= coins[i]: dp[i][a] = dp[i + 1][a] dp[i][a] += dp[i][a - coins[i]] return dp[0][amount]
Java
public class Solution { public int change(int amount, int[] coins) { int n = coins.length; Arrays.sort(coins); int[][] dp = new int[n + 1][amount + 1]; for (int i = 0; i <= n; i++) { dp[i][0] = 1; } for (int i = n - 1; i >= 0; i--) { for (int a = 0; a <= amount; a++) { if (a >= coins[i]) { dp[i][a] = dp[i + 1][a]; dp[i][a] += dp[i][a - coins[i]]; } } } return dp[0][amount]; } }
C++
class Solution { public: int change(int amount, vector& coins) { int n = coins.size(); sort(coins.begin(), coins.end()); vector > dp(n + 1, vector (amount + 1, 0)); for (int i = 0; i <= n; i++) { dp[i][0] = 1; } for (int i = n - 1; i >= 0; i--) { for (int a = 0; a <= amount; a++) { if (a >= coins[i]) { dp[i][a] = dp[i + 1][a]; dp[i][a] += dp[i][a - coins[i]]; } } } return dp[0][amount]; } };
JavaScript
class Solution { /** * @param {number} amount * @param {number[]} coins * @return {number} */ change(amount, coins) { coins.sort((a, b) => a - b); const n = coins.length; const dp = Array.from({ length: n + 1 }, () => Array(amount + 1).fill(0)); for (let i = 0; i <= n; i++) { dp[i][0] = 1; } for (let i = n - 1; i >= 0; i--) { for (let a = 0; a <= amount; a++) { if (a >= coins[i]) { dp[i][a] = dp[i + 1][a]; dp[i][a] += dp[i][a - coins[i]]; } } } return dp[0][amount]; } }