繁体   English   中英

创建一个使用递归在 kotlin 中生成所有字符串排列的方法

[英]Creating a method that generates all permutations of string in kotlin using recursion

尝试编写一些代码来生成输入字符串的所有排列作为递归练习,但无法弄清楚为什么会出现堆栈溢出错误。

fun main() {
    println(subSet(listOf("abcd")))
}

fun subSet(s: List<String>): List<String>{
    return listOf<String>() + createSubSets(s)
}

fun createSubSets(s: List<String>): List<String>{
    if(s.isEmpty()){
        return listOf()
    }
    return s.mapIndexed{i, elem ->
        elem + createSubSets(s.drop(i))
    }
}

这个语句导致无限递归:

return s.mapIndexed { i, elem ->
    elem + createSubSets(s.drop(i))
}

其中,第一次迭代的i值为0elem是索引0处的字符),递归调用createSubSets(s.drop(i))等效于createSubSets(s) ,因为从字符串返回原始字符串。

你的递归函数不安全。 它永远迭代,不断添加到堆栈中,这就是为什么您会遇到堆栈溢出。

除了修复你的算法,你可以做两件事来改善这种情况:

  1. 添加退出条件,使函数最终退出。
fun main() {
    println(subSet(listOf("a", "b", "c", "d")))
}

fun subSet(s: List<String>): List<String>{
    return createSubSets(s, 0)
}

fun createSubSets(s: List<String>, index: Int): List<String> {
    if (index > s.lastIndex) {
        return emptyList()
    }
    val otherElements = s.subList(0, index) + s.subList(index + 1, s.size)
    val element = s[index]
    return otherElements.map { element + it } + createSubSets(s, index + 1)
}

// [ab, ac, ad, ba, bc, bd, ca, cb, cd, da, db, dc]
  1. 使函数尾递归,这样即使是长字符串也不会堆栈溢出。
fun main() {
    println(subSet(listOf("a", "b", "c", "d")))
}

fun subSet(s: List<String>): List<String>{
    return createSubSets(s, 0, emptyList())
}

tailrec fun createSubSets(s: List<String>, index: Int, carryOn: List<String>): List<String> {
    if (index > s.lastIndex) {
        return carryOn
    }
    val otherElements = s.subList(0, index) + s.subList(index + 1, s.size)
    val element = s[index]
    return createSubSets(s, index + 1, carryOn + otherElements.map { element + it })
}

// [ab, ac, ad, ba, bc, bd, ca, cb, cd, da, db, dc]

请注意,尾递归版本总是将自己称为最后一件事。 具体来说,它不会对调用自身的结果执行任何操作。 这就是它必须将结果传递到下一次调用的原因,但这也是它堆栈安全的原因。

最后,请注意您根本不需要递归来解决这个问题:

fun main() {
    println(subSet(listOf("a", "b", "c", "d")))
}

fun subSet(s: List<String>): List<String>{
    return createSubSets(s)
}

fun createSubSets(s: List<String>): List<String> {
    return s.mapIndexed { i, element ->
        val otherElements = s.subList(0, i) + s.subList(i + 1, s.size)

        otherElements.map { element + it }
    }.flatten()
}

// [ab, ac, ad, ba, bc, bd, ca, cb, cd, da, db, dc]
fun main() {
permutations("abcd","")   }
                                         
fun permutations(str:String, storedString: String){
if(str.length == 1)
    println(storedString+str)
else
for(i in str.indices)
    permutations(str.removeRange(i,i+1),storedString+str[i])}

另一个例子:

fun String.permute(result: String = ""): List<String> =
    if (isEmpty()) listOf(result) else flatMapIndexed { i, c -> removeRange(i, i + 1).permute(result + c) }

fun main() {
    println("abc".permute()) // [abc, acb, bac, bca, cab, cba]
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM