【问题标题】:coins change dp solution - why the order of iterative loop matter硬币改变 dp 解决方案 - 为什么迭代循环的顺序很重要
【发布时间】:2020-01-16 13:26:02
【问题描述】:

为什么迭代循环的顺序在这里很重要?

    def change1(self, amount, coins):
        """
        :type amount: int
        :type coins: List[int]
        :rtype: int
        """
        if amount == 0:
            return 1

        dp = [0 for _ in range(amount + 1)]
        dp[0] = 1

        # dp[i] to denote the number of ways to sum up to amount i.
        for j in range(len(coins)): # switch those 2 statements would be wrong answer why???
            for i in range(1, amount + 1):
                if i - coins[j] >= 0:
                    dp[i] += dp[i - coins[j]]

        return dp[amount]

    def change2(amount, coins): # wrong answer
        """
        :type amount: int
        :type coins: List[int]
        :rtype: int
        """
        if amount == 0:
            return 1

        dp = [0 for _ in range(amount + 1)]

        ## when amount is 0, # combinations is 1
        dp[0] = 1

        # dp[i] to denote the number of ways to sum up to amount i.
        for i in range(1, amount + 1):
            for j in range(len(coins)):  # switch those 2 statements would be wrong answer why???
                if i - coins[j] >= 0:
                    dp[i] += dp[i - coins[j]]

        return dp[amount]

更改 1

dp[i-1] = dp[i-1-c2] + dp[i-1-c2] + dp[i-2-c2] + ..dp[0]

dp[i] = dp[i-c1] + dp[i-1-c1] + dp[i-2-c1] + ...dp[0] 这是正确的解决方案。

更改 2

dp[i-1] = dp[i-1-c1] + dp[i-1-c2] + dp[i-1-c3] + dp[i-1-c4] + ... dp[0]

dp[i] = dp[i-c1] + dp[i-c2] + dp[i-c3] + dp[i-c4] + ... dp[0]

为什么这种方法是错误的?

总金额i可以从取币c1c2c3的选择总和得出,我认为这更直观。

我检查了一些参考资料,但找不到令人满意的答案。

编辑:我也明白改变嵌套循环的顺序会给出错误的答案,我试图理解为什么第二种方法有错误的直觉,而第一种方法是正确的。

Coin Change: number of solutions when order matters vs. when order doesn't matter

Coin change using dynamic programming

【问题讨论】:

    标签: algorithm dynamic-programming


    【解决方案1】:

    显然,当您更改嵌套循环的顺序时,它必须给出错误的答案。

    问题的正确dp状态定义如下:

    dp[i][j] = # of ways to form amount j using first i coins
    

    这里的最佳子结构是,一旦你有了第一个i 硬币的解决方案,你就可以将它扩展到i+1 硬币。

    但是当你翻转循环的执行顺序时,这个子结构属性就不成立了。

    在这种情况下,您首先使用所有硬币计算形成金额i 的方式数,并将其扩展以找到形成金额i+1 的方式数,其中最优子结构属性不成立真的。

    【讨论】:

    • 我没有使用dp[i][j] 而是dp[amount] 表示求和i 的方式数。根据定义,应该是dp[amount] = dp[amount-c1] + dp[amount-c2] ...
    • 为了解释的简单,我使用了dp[i][j]。如果你仔细看,dp[n][amount] 上定义的dp 状态等同于dp[amount],在每次迭代中,不是更新原始dp 数组,而是每次迭代都有一个新行。 stackoverflow.com/questions/27880842/…
    • 是的,如果您从 dp[i][j] 进行优化,这种解释是有道理的,但是,上面的dp[amount]denotation 有什么问题 - 使用任何硬币求和的方式数
    • 谢谢,在我的情况下,dp[amount] 的基本表示是错误的,dp[amount] 实际上是总计 i 的方式数,using the first j coins
    猜你喜欢
    • 2018-02-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 2015-09-02
    • 1970-01-01
    • 1970-01-01
    • 2023-01-31
    • 1970-01-01
    相关资源
    最近更新 更多