零钱兑换 II
零钱兑换 II
https://leetcode-cn.com/problems/coin-change-2/
此题是完全背包问题,即物品数量是无限的。
动态规划
对于背包问题,DP 表 dp[i][j] 表示:若只使用 coins 中的前 i 个硬币的面值,若想凑出金额 j,有 dp[i][j] 种凑法。
- 如果你不把这第 
i个物品装入背包,也就是说你不使用coins[i]这个面值的硬币,那么凑出面额 j 的方法数dp[i][j]应该等于dp[i-1][j],继承之前的结果。 - 如果你把这第 
i个物品装入了背包,也就是说你使用coins[i]这个面值的硬币,那么dp[i][j]应该等于dp[i][j-coins[i-1]]。(注意这里是 dp[i][j-coins[i-1]] ,已经包括了再次重复使用这个硬币的情况) 
综上就是两种选择,而我们想求的 dp[i][j] 是「共有多少种凑法」,所以 dp[i][j] 的值应该是以上两种选择的结果之和:
1  |  | 
压缩 DP 表
可以看出 dp[i][..] 的状态总是且仅依赖于 dp[i-1][..] 的状态,因此可以只使用 1D 数组来完成, 每次在数组上迭代就相当于 i 的递增。
1  |  | 
与 分割等和子集 不同,这里压缩 DP 表不需要从后遍历 j,因为观察压缩前的状态转移公式,dp[i-1][j] 只会用于更新 dp[i][j],可以直接覆盖掉而不影响其它结果。
(在上一题中,dp[i-1][j] 可能会用于更新 dp[i][j + nums[i]] 的值,如果从头开始遍历,更新到 dp[i-1][j + nums[i]] 时,dp[i-1][j] 已经先于它更新了。