【问题标题】:Leetcode coin change timeoutLeetcode 硬币找零超时
【发布时间】:2020-12-16 07:59:55
【问题描述】:

https://leetcode.com/problems/coin-change

以下输入超时,如果 19 -> 18 或更少,则通过。

[1,2,5]
19
// e.g. n === [1, 2, 5]
// e.g. t === target sum 
// c === counter, count each level
// h === hash, memo
var cc = function(n, t, c, h) {
    // index
    const index = t;
    // if we saw before, return it
    if(h[index]) {
        return h[index];
    }
    else if(t === 0) {
        // we use all the target, return the counter
        return c;
    }

    // mi === minimum counter
    let mi = Infinity;
    // e.g. we loop [1, 2, 5]
    for(let i=0; i<n.length; i++) {
        // only allow positive
        if(t-n[i] >= 0) {
            // recursive
            // mi === Infinity
            // t-n[i], consume it
            // c+1, increase the counter
            // h, pass down the hash
            mi = Math.min(mi, cc(n, t-n[i], c+1, h));
        }
    }

    // Update h[index] when mi < h[index]
    h[index] = mi < h[index] ? mi : h[index];
    return mi;
}


var coinChange = function(n, t) {
    const res = cc(n, t, 0, {});
    const out = res === Infinity ? -1 : res;
    return out;
};

有人知道出了什么问题吗?

标签: algorithm recursion dynamic-programming


【解决方案1】:

代码至少有一个问题。要查看一个,请更改此行:

h[index] = mi < h[index] ? mi : h[index];

到这里:

console.log(`Before: t: ${ t }, mi: ${ mi }, h[index]: ${ h[index] }`);
h[index] = mi < h[index] ? mi : h[index];
console.log(`After: t: ${ t }, mi: ${ mi }, h[index]: ${ h[index] }`);

然后调用:

console.log(coinChange([1,2,5], 3));

我认为,另一个问题是想要更新h[index] 中记录的结果,但同时又想要在我们进行更新之前返回存储在其中的结果之间的差异。

想象我们可以通过各种方式到达目标 0,所以想想如果第一个递归分支通过多步路径到达那里,当前会发生什么。

【讨论】:

    【解决方案2】:

    以下是能够通过测试用例的。

    修正了何时更新哈希

    // keep it infinity or 0 or positive
    h[index] = (h[index] === undefined ? mi : mi < h[index] ? mi : h[index]);
    

    计数器只发生在函数内部。没有混淆

    result = cc(n, t-n[i], h)
    
    var cc = function(n, t, h) {
        // index
        const index = t;
        // reach 0, re 0
        if(t === 0) {
            return 0;
        } else if(h[index] !== undefined) {
            // hash
            return h[index];
        }
    
        // min
        let mi = Infinity;
        // loop coin
        for(let i=0; i<n.length; i++) {
            // posi, get in
            if(t-n[i] >= 0) {
                // return count or hash
                mi = Math.min(mi, cc(n, t-n[i], h)+1);
            }
        }
    
        // keep it infinity or 0 or positive
        h[index] = (h[index] === undefined ? mi : mi < h[index] ? mi : h[index]);
        return h[index];
    }
    
    
    var coinChange = function(n, t) {
        const res = cc(n, t, {});
        const out = res === Infinity ? -1 : res;
        return out;
    };
    

    【讨论】:

    • h[index] = (h[index] === undefined... 怎么会评估为“已定义”?如果定义了h[index],我们不是在cc 函数的顶部返回它的值吗?那个时候是不是总是未定义,所以我们可以把它设置为mi
    【解决方案3】:

    如果我们使用额外的内存来解决问题,也许会更容易:

    const coinChange = function(coins, amount) {
        const inf = Math.pow(2, 31)
        const dp = []
        dp[0] = 0
    
        while (dp.length <= amount) {
            let curr = inf - 1
            for (let index = 0; index < coins.length; index++) {
    
                if (dp.length - coins[index] < 0) {
                    continue
                }
    
                curr = Math.min(curr, 1 + dp[dp.length - coins[index]])
            }
    
            dp.push(curr)
        }
    
        return dp[amount] == inf - 1 ? -1 : dp[amount]
    };
    

    Python:

    class Solution:
        def coinChange(self, coins, target):
            dp = [0] + [float('inf')] * target
            for index in range(1, target + 1):
                for coin in coins:
                    if index - coin >= 0:
                        dp[index] = min(dp[index], dp[index - coin] + 1)
            
            return -1 if dp[-1] == float('inf') else dp[-1]
    

    使用辅助函数(Java):

    class Solution {
        public int coinChange(int[] coins, int target) {
            if (target < 1)
                return 0;
            return helper(coins, target, new int[target]);
        }
    
        private int helper(int[] coins, int rem, int[] count) {
            if (rem < 0)
                return -1;
            if (rem == 0)
                return 0;
            if (count[rem - 1] != 0)
                return count[rem - 1];
            int min = Integer.MAX_VALUE;
            for (int coin : coins) {
                int res = helper(coins, rem - coin, count);
                if (res >= 0 && res < min)
                    min = 1 + res;
            }
    
            count[rem - 1] = (min == Integer.MAX_VALUE) ? -1 : min;
            return count[rem - 1];
    
        }
    }
    

    参考

    • 有关更多详细信息,请参阅Discussion Board,您可以在其中找到大量解释清楚且公认的解决方案,其中包含各种languages,包括低复杂度算法和渐近runtime/memory 分析@ 987654325@, 2.

    【讨论】:

    • 这如何回答 OP 的问题,“出了什么问题?” (及其实施)
    • 嘿。在网上找到硬币找零问题的现成解决方案并不难。当然,这不是我们来这里的目的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-09
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2015-07-03
    • 1970-01-01
    相关资源
    最近更新 更多