简体   繁体   English

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

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

trying to write some code that generates all permutations of an input string as a recursion exercise but can't figure out why I get a stack overflow error.尝试编写一些代码来生成输入字符串的所有排列作为递归练习,但无法弄清楚为什么会出现堆栈溢出错误。

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))
    }
}

This statement leads to infinite recursion:这个语句导致无限递归:

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

In it, the first iteration has the i value of 0 (with the elem being the character at index 0 ), and the recursive call createSubSets(s.drop(i)) is equivalent to createSubSets(s) , because dropping zero characters from a string returns the original string.其中,第一次迭代的i值为0elem是索引0处的字符),递归调用createSubSets(s.drop(i))等效于createSubSets(s) ,因为从字符串返回原始字符串。

Your recursive function is not safe.你的递归函数不安全。 It iterates forever, keeps adding to the stack and that's why you're getting a stack overflow.它永远迭代,不断添加到堆栈中,这就是为什么您会遇到堆栈溢出。

Apart from fixing your algorithm, you can do two things to improve the situation:除了修复你的算法,你可以做两件事来改善这种情况:

  1. Add an exit condition to make the function exit eventually.添加退出条件,使函数最终退出。
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. Make the function tail-recursive so that even with long strings it won't stack overflow.使函数尾递归,这样即使是长字符串也不会堆栈溢出。
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]

Notice that the tail-recursive version always calls itself as the last thing.请注意,尾递归版本总是将自己称为最后一件事。 Specifically, it doesn't perform any operations on the result of calling itself.具体来说,它不会对调用自身的结果执行任何操作。 That's why it has to carry on the result to the next call, but that is also why it's stack safe.这就是它必须将结果传递到下一次调用的原因,但这也是它堆栈安全的原因。

Finally, notice that you don't need recursion at all to solve this problem:最后,请注意您根本不需要递归来解决这个问题:

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])}

Another example:另一个例子:

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