#每日n题#找零钱

58 阅读1分钟

前言

做这道题的时候我也陷入了爬楼梯的误区……
其实只需要清楚一点,对于爬楼梯来说:

但对于零钱来说,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]];
    }
  }

image.png 这个时候按面额填表,1 → 2 → 5。
参考:leetcode-cn.com/problems/co…

题外话:面试的时候被问到这个问题,我又想不起来了。觉得自己还是对动态规划的问题理解不到位……