前言
做这道题的时候我也陷入了爬楼梯的误区……
其实只需要清楚一点,对于爬楼梯来说:
但对于零钱来说,amount = 3
时,(1, 2)
和 (2, 1)
这两种组合没有区别。这就是排列和集合的问题,排列是顺序相关的,用A(x, y)
计算组合数;集合是顺序无关的,用 C(x, y)
计算。
如何去重
先参考一下爬楼梯的方案:
var climbStairs = function (n) {
let dp = [];
dp[1] = 1;
dp[2] = 2;
for (let i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n]
};
楼梯只有 1 级或 2 级的走法,而在找零钱的时候,需要遍历所有面额种类,然后把所有选择对应的选择数相加即可:
// 遍历总钱数
for (let j = 0; j <= amount; j++) {
// 遍历面额
for (let i = 0; i < coins.size(); i++) {
if (j - coins[i] >= 0) dp[j] += dp[j - coins[i]];
}
}
这个时候按总数填表,对于每个总数,所有的物品重量都会考虑,说明最后得出的结果是有序的。想要去重,保留一种顺序的结果即可。
// 遍历面额数
for (let i = 0; i < coins.size(); i++) {
// 遍历总钱数
for (let j = coins[i]; j <= amount; j++) {
dp[j] += dp[j - coins[i]];
}
}
这个时候按面额填表,1 → 2 → 5。
参考:leetcode-cn.com/problems/co…
题外话:面试的时候被问到这个问题,我又想不起来了。觉得自己还是对动态规划的问题理解不到位……