当前位置: 首页 > 知识库问答 >
问题:

导致堆栈溢出的Kotlin尾部递归函数

长孙瑞
2023-03-14

我正在研究这个简单的问题来练习基本Kotlin,在递归返回行上遇到了堆栈溢出,代码如下:

class Solution {
    fun isPalindrome(s: String): Boolean {
        val cleaned = s.toLowerCase().replace(Regex("[^a-z0-9]"), "")
        tailrec fun isPalindrome(start: Int, end: Int): Boolean {
            if (start >= end) return true
            return cleaned[start] == cleaned[end] && isPalindrome(start+1, end-1)
        }
        return isPalindrome(0, cleaned.length-1)
    }
}

我对tailrec的理解是,它应该将递归函数转换为迭代函数,而迭代函数不会受到这种崩溃的影响。如果我没有正确实现尾部递归,编译器应该会发出错误。

有人能解释一下为什么这会像标准递归调用一样在大输入上崩溃吗?

共有1个答案

缪成天
2023-03-14

这种行为看起来像是短路运算符中尾部调用的缺失优化,其中正在计算最后一个操作数的事实意味着表达式结果不再依赖于之前的操作数。

同时,您可以将返回语句重写为

return if (cleaned[start] != cleaned[end]) false else isPalindrome(start+1, end-1)

为了得到相同的结果,尾部调用优化。

 类似资料:
  • 问题内容: 这有效:http : //play.golang.org/p/-Kv3xAguDR。 这导致堆栈溢出:http : //play.golang.org/p/1-AsHFj51O。 我不明白为什么。在这种情况下,使用接口的正确方法是什么? 问题答案: 这个 将呼叫您的,依次呼叫,等等。如果您需要解组JSON然后对其进行处理,那么一种巧妙的技术是声明一个本地类型,将数据解组到其中,然后转换

  • 假设我编写这样的代码: 我如何让Kotlin优化这些相互递归的函数,以便在不抛出StackOverflower错误的情况下运行main?tailrec关键字适用于单函数递归,但没有更复杂的功能。我还看到一个警告,在使用关键字tailrec的地方没有找到尾部调用。也许这对编译器来说太难了?

  • 我正在使用一个正则表达式从任意长的输入字符串中提取键值对,并且遇到了这样的情况:对于具有重复模式的长字符串,它会导致堆栈溢出。 KV解析代码如下所示: 一些虚构的输出示例: 我显式地将generic放在上面,而不是在解析之前检查最大字符串长度的hacks(例如)。 我能想出的最粗俗的解决方法,一个真正的反模式,是 有趣的是,它在我试过的几次运行中都起作用了,但它不是一个值得推荐的有品位的东西。:-

  • 我正在做一个EclipseLink项目,在这个项目中,一个用户可以“跟踪”另一个用户,就像在社交媒体网站上一样。我使用实体(引用了一个名为的表)进行了设置,该实体具有一个“followers”(跟随该用户的用户)列表和另一个“followed”(该用户正在跟随的用户)列表。该关系在一个名为的单独表中定义,该表包含以下用户的ID()和以下用户的ID()的列。 我的用户模型如下所示: 方法似乎工作得很

  • 我找不到堆栈溢出的来源,但似乎是外部的循环造成的。 提前道谢!

  • 我在Kotlin中编写了这个递归函数: 它将运行不确定的次数(因为我在进化算法中使用随机性来收敛解)。我经常得到堆栈溢出。静态编程语言/JVM语言的最大堆栈深度是多少?我应该只编写非递归函数吗?