【问题标题】:String permutation recursion issue字符串排列递归问题
【发布时间】:2023-04-11 09:51:01
【问题描述】:

(--这个问题在下面得到了回答--)

大家好,所以我知道这个问题到目前为止已经在这个网站上以各种方式得到了回答,但我想看看我是否可以在没有得到直率答案的情况下得到我的问题的提示......对不起,如果这是多余的!

所以...到目前为止我的代码是这样的(正如函数所说,这应该打印出字符串“ABCD”的每个排列,并且必须递归地完成并且不使用 STL 算法):

void printPermutations(string prefix, string remainder)
{
    
    if (remainder.empty())        
        cout<<prefix<<endl;         
    else {
        for(int i = 0; i<remainder.length(); i++)      
        {
            prefix += remainder[i];                     
            remainder = (remainder.substr(0, i) + remainder.substr(i+1));    //Gets rid of selected char
            printPermutations(prefix, remainder);   //recursion w/updated values. Problem here?
         }
     }
}

其中余数 = "ABCD" 作为测试字符串。我假设我的问题出在递归调用本身?

到目前为止,该函数只打印出前 3 个排列:ABCD、ABDC、ACBD。我也有一种预感,这可能与 for 控制有关,因为它打印出 3 个排列,而 3 会小于字符串的长度 4?我不知道。我刚开始学习递归,我真的很难弄清楚如何正确地实现递归调用。

【问题讨论】:

  • 欢迎来到 Stack Overflow。请阅读the help pages,接受SO tour,阅读How to Ask,以及this question checklist。最后请学习如何edit您的问题,例如包含一个实际问题。您显示的代码有什么问题?您在哪些方面需要我们的帮助?
  • 你想达到什么目的?如果这就是我认为我不确定它是否可以递归完成。
  • 排列不需要递归,可以通过递归来组合。
  • @samthegolden 任何循环都可以递归完成,所以这可以通过递归来完成,但我不确定它是否有必要。
  • 你是对的@john

标签: c++ recursion


【解决方案1】:

问题是您正在修改循环中的两个字符串,所以prefix 增长而remainder 缩小。

也就是说,您希望“顶级”调用遍历 A/BCD、B/ACD、C/ABD 和 D/ABC,但您正在遍历 A/BCD、AB/CD、ABC /D 和 ABCD/空。

不要修改字符串,只需将你想要的值传递给递归:

void printPermutations(string prefix, string remainder)
{
    if (remainder.empty())        
        cout<<prefix<<endl;         
    else {
        for(int i = 0; i<remainder.length(); i++)      
        {
            printPermutations(prefix + remainder[i], 
                              remainder.substr(0, i) + remainder.substr(i+1));
        }
    }
} 

如果您想要更“逐步”的外观,请使用“新鲜”变量:

void printPermutations(string prefix, string remainder)
{
    if (remainder.empty())        
        cout<<prefix<<endl;         
    else {
        for(int i = 0; i<remainder.length(); i++)      
        {
            string thisPrefix = prefix + remainder[i];
            string thisRemainder = remainder.substr(0, i) + remainder.substr(i+1);
            printPermutations(thisPrefix, thisRemainder);
        }
    }
}

【讨论】:

  • 我明白了。非常感谢您的回答。我不知道为什么我没有想到在不传递原始字符串的情况下传递更新的值。我很难“看到”递归调用在未来的调用中会做什么。我画出了这棵树,它是有道理的,但是我不知道如何正确地实现它。
  • 另外,只是为了澄清以供将来参考:将其视为树的一条腿首先完成然后它回到顶部并完成第二条腿是否正确?比如说 A 是前缀 -> 整个 A 树完成,然后它回到原来的 for 循环并将 B 设置为前缀 -> B 树完成等等?
  • @s0rry 是的,这就是循环所说的 - “打印以'A'开头的排列,打印以'B'开头的排列,......(您还可以添加跟踪输出并查看。向函数添加“深度”参数,以便您可以看到自己的位置会有所帮助 - 这就是我所做的,以查看您的代码在做什么。)
【解决方案2】:

请考虑使用 stl 算法 next_permutation 来完成这项工作。你的情况下的代码是:

#include <algorithm>
#include <string>
#include <iostream>
 
int main()
{
    std::string s = "ABCD";
    std::sort(s.begin(), s.end());
    do {
        std::cout << s << '\n';
    } while(std::next_permutation(s.begin(), s.end()));
}

如果需要,可以围绕这个 sn-p 编写一个包装器。

【讨论】:

  • 感谢您的回答,但我们不允许使用任何 STL 算法。这是针对课堂上的递归项目。
  • @s0rry 你可以从 stl 算法中学习这个任务是如何完成的。 cppreference.com 上的文档(答案中的链接)显示了一种可能的实现方式。
  • 我明白了。我觉得教授会对我们不屑一顾,而不是自己努力解决问题,但是通过递归,您有时似乎碰壁了,不得不寻求提示。感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 2020-03-05
  • 1970-01-01
  • 1970-01-01
  • 2012-08-24
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
  • 2011-11-22
相关资源
最近更新 更多