【问题标题】:Kotlin Coin Change recursive functional approachKotlin Coin Change 递归函数方法
【发布时间】:2022-11-03 11:19:11
【问题描述】:

我正在尝试用下一个基本思想解决leetcode problem

fun coinChange(coins: IntArray, amount: Int): Int {
    fun calc(source: Long, lvl: Int): Int =
        if (source == amount.toLong())
            lvl
        else if (source > amount)
            -1
        else
            coins
                .map { calc(source = source + it, lvl = lvl + 1) }
                .filter { it > 0 }
                .sorted()
                .firstOrNull() ?: -1


    return calc(source = 0, lvl = 0)
}

这个算法看起来是正确的,但它非常慢并且由于堆栈溢出而无法通过测试。在那种情况下,我试图加快一点速度,但现在它无法正常工作:

fun coinChange(coins: IntArray, amount: Int): Int {
    val memoized = mutableMapOf<Int, Int>()

    fun calc(source: Int, lvl: Int): Int =
        if (source == amount)
            lvl
        else if (source > amount)
            -1
        else
            memoized.getOrElse(source) {
                val evaluated = coins
                    .reversed()
                    .map { calc(source = source + it, lvl = lvl + 1) }
                    .filter { it > 0 }
                    .minOrNull() ?: -1

                memoized[source] = evaluated
                evaluated
            }

    return calc(source = 0, lvl = 0)
}

对于输入coinChange(coins = intArrayOf(186, 419, 83, 408), amount = 6249),它返回36,但必须是20。你会帮助我吗?

【问题讨论】:

  • 似乎您的问题与算法有关,因此如果您先解释您的方法,则更容易解决
  • @AbhinavMathur 我的方法是通过源代码描述的。我以声明方式使用经典的“执行树”。
  • 对于那些不熟悉 Java/Kotlin 的人来说,这很难读,因为这是一种常见的算法。除非错误的答案是实现的结果,否则算法解释会更好(这只是我的观点,其他人可能会觉得这更容易阅读)

标签: java algorithm kotlin functional-programming


【解决方案1】:

Kotlin(Scala 和 Swift 也是)函数式编程方面被高估了。在您的代码中: reversed、map 和 filter 触发 3 个循环。所以最好只做常规的 for/while 循环。每个调用触发 3 个循环(虽然可以通过一个循环来完成),您的性能会受到很大影响。我研究了 Kotlin 的记忆机制,但没有找到适合递归函数的机制。 (我想被指出/受过教育)(这个https://stackoverflow.com/a/35309775 和类似的类方法不起作用。我必须手动管理缓存)好吧,我的抱怨已经够多了,这是手动管理缓存的解决方案,通过 189 / 189 次测试

fun coinChange(coins: IntArray, amount: Int): Int {
    val cache = mutableMapOf<Pair<Int, Int>, Int>()
    fun dfs(p:Pair<Int, Int>):Int{
        cache[p]?.let{return it}
        val (idx, amount) = p
        val ans = if(amount == 0) 0
        else{
            var count = Int.MAX_VALUE
            for(i in idx until coins.size){ 
                val nxt = amount - coins[i]
                if(nxt < 0) continue
                val res = dfs(i to nxt) 
                if(res == Int.MAX_VALUE) continue
                count = Math.min(count, res + 1)
            }
            count 
        }
        cache[p] = ans
        return ans
    }
    coins.sort()
    coins.reverse()
    val ans = dfs(0 to amount)
    return if(ans != Int.MAX_VALUE) ans else -1
}

这是未经请求的python代码。使用简单的装饰器 @cache 可以很好地完成缓存

def coinChange(self, coins: List[int], amount: int) -> int:
    @cache
    def dfs(idx, target):
        if target == 0:
            return 0
        result = float('Inf')
        for i in range(idx, len(coins)):
            if target - coins[i] < 0: continue 
            result = min(result, 1 + dfs(idx, target - coins[i]))
        return result
    coins.sort(reverse=True) 
    ans = dfs(0, amount)
    return -1 if ans == float('Inf') else ans 

这是另一种手动记忆的递归方法

fun coinChange(coins: IntArray, amount: Int): Int { 
    val MAX:Long = Int.MAX_VALUE.toLong()
    val cache = mutableMapOf<Pair<Int, Int>, Long>()
    fun dfs(p:Pair<Int, Int>):Long{
        cache[p] ?. let{return it}
        val (idx, amount) = p
        val ans =   if(amount == 0) 0
                    else if(amount < 0 || idx == coins.size) MAX
                    else Math.min(dfs(idx + 1 to amount), 1 + dfs(idx to amount - coins[idx]))
        cache[p] = ans
        return ans
    }
    val ans = dfs(0 to amount) 
    return if(ans == MAX) -1 else ans.toInt()
}

和 Python 计数器部分

def coinChange(self, coins: List[int], amount: int) -> int:
    @cache
    def dfs(idx, amount):
        if amount == 0: return 0
        if amount < 0 or idx == len(coins): return float('Inf')
        return min(dfs(idx + 1, amount), 1 + dfs(idx, amount - coins[idx]))
    ans = dfs(0, amount)
    return ans if ans != float('Inf') else -1

【讨论】:

    猜你喜欢
    • 2018-06-16
    • 2016-06-13
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 2016-04-07
    • 1970-01-01
    • 2020-04-04
    • 1970-01-01
    相关资源
    最近更新 更多