【问题标题】:Recursive Function that returns all substrings of a string返回字符串的所有子字符串的递归函数
【发布时间】:2015-05-27 12:03:07
【问题描述】:

我需要用 C++ 实现一个函数,

vector<string> generateSubstrings(string s),

返回一个字符串的所有子字符串的向量。例如,字符串“rum”的子字符串是七个字符串

“r”、“ru”、“rum”、“u”、“um”、“m”、“”。

函数必须是递归的,并且必须将结果作为向量返回。

到目前为止,这是我的代码。它只打印“r”、“ru”和“rm”。我在实现这个功能时遇到了很多麻烦。在过去的几个小时里,我一直在研究这个问题,但我只是不知道如何让它按规定工作,所以任何帮助都将不胜感激。

#include <iostream>
#include <string>
#include <vector>

using namespace std;

vector<string> generateSubstrings(string s, int num){ 
    int index = num;
    int SIZE = s.size();

    vector<string> substrings;


    if(index == s.size()){//BASE CASE
        string temp = s.substr(index,1);
        substrings.push_back(temp);
    }
    else{
        for(int i = 0; i < SIZE; ++i){ 
            string temp = s.at(index) + s.substr(i,i);
            substrings.push_back(temp);
        }   
        generateSubstrings(s, num + 1);
    }     
    return substrings; 
} 

int main() { 
    vector<string> vec(20);
    vec = generateSubstrings("rum", 0);


    cout << endl << endl;cout << "PRINTING VECTOR" << endl;

    for ( int i = 0; i<vec.size();++i){
        cout << vec.at(i);
        cout << endl;
    }
    cout << "DONE";
}

【问题讨论】:

  • “rumm”的子串是什么?它有两个“m”子字符串还是应该只有其中一个?

标签: c++ string recursion vector substring


【解决方案1】:

在你的作业中写到递归函数必须像这样声明

vector<string> generateSubstrings(string s),

但你正试图让另一个函数递归声明为

vector<string> generateSubstrings(string s, int num);

所以无论如何你的解决方案都不能满足作业的要求。

函数可以如下所示

#include <iostream>
#include <string>
#include <vector>

std::vector<std::string> generateSubstrings( std::string s )
{
    if ( s.empty() ) return {};

    std::vector<std::string> v;
    v.reserve( s.size() * ( s.size() + 1 ) / 2 );

    for ( std::string::size_type i = 0; i < s.size(); i++ )
    {
        v.push_back( s.substr( 0, i + 1 ) );
    }

    for ( const std::string &t : generateSubstrings( s.substr( 1 ) ) )
    {
        v.push_back( t );
    }

    return v;
}

int main() 
{
    std::string s( "rum" );

    for ( const std::string &t : generateSubstrings( s ) )
    {
        std::cout << t << std::endl;
    }

    return 0;
}

它的输出是

r
ru
rum
u
um
m

如果您还需要包含一个空字符串,那么您应该更改条件

    if ( s.empty() ) return {};

以适当的方式。例如

   if ( s.empty() ) return { "" };

同样在这种情况下你应该写

   v.reserve( s.size() * ( s.size() + 1 ) / 2 + 1 );

您也可以用方法插入替换所示函数中的循环。例如

#include <iostream>
#include <string>
#include <vector>

std::vector<std::string> generateSubstrings( std::string s )
{
    if ( s.empty() ) return {};

    std::vector<std::string> v;
    v.reserve( s.size() * ( s.size() + 1 ) / 2 );

    for ( std::string::size_type i = 0; i < s.size(); i++ )
    {
        v.push_back( s.substr( 0, i + 1 ) );
    }

    std::vector<std::string> v2 = generateSubstrings( s.substr( 1 ) );

    v.insert( v.end(), v2.begin(), v2.end() );

    return v;
}

int main() 
{
    std::string s( "rum" );

    for ( const std::string &t : generateSubstrings( s ) )
    {
        std::cout << t << std::endl;
    }

    return 0;
}

程序输出将与上图相同。

这是一个在向量中包含一个空字符串的程序修改。

#include <iostream>
#include <string>
#include <vector>

std::vector<std::string> generateSubstrings( std::string s )
{
    if ( s.empty() ) return { "" };

    std::vector<std::string> v;
    v.reserve( s.size() * ( s.size() + 1 ) / 2 + 1 );

    for ( std::string::size_type i = 0; i < s.size(); i++ )
    {
        v.push_back( s.substr( 0, i + 1 ) );
    }

    std::vector<std::string> v2 = generateSubstrings( s.substr( 1 ) );

    v.insert( v.end(), v2.begin(), v2.end() );

    return v;
}

int main() 
{
    std::string s( "rum" );

    for ( const std::string &t : generateSubstrings( s ) )
    {
        std::cout << t << std::endl;
    }

    return 0;
}

【讨论】:

  • 我有一个问题,当您执行for ( const std::string &amp;t : generateSubstrings( s ) ) 时,是否每次都会评估generateSubstrings( s )
  • @Guiroux 它只计算一次。
  • 我不断收到一条错误消息,“引用变量“t”需要一个初始化程序。”我不知道如何解决这个问题,因为我不熟悉你用于那些 for 循环的语法。
  • 此语法为 C++11 标准,例如 g++ 必须使用 -std=c++11 选项
  • @Domino 使用函数的第二个修改。它不使用基于范围的 for 循环。至于 main 中的循环,那么您可以随意编写 main 而不使用循环。:)
【解决方案2】:

首先,您应该注意代码缩进。 然后,我不看你的代码,我写了一些代码来实现你的目的,如下:

void generateSubstrings(string s, int num, vector<string> &sta)
{
    if (num == s.size())
        return;

    auto b = begin(s) + num;

    string temp = "";
    temp += *b;
    sta.push_back(temp);
    b++;
    while (b != end(s))
    {

        temp += *b;
        sta.push_back(temp);
        b++;

    }
    generateSubstrings(s, num + 1, sta);
}

【讨论】:

  • 这段代码和问题有什么不同?请添加解释,以便其他用户可以从此答案中受益。此答案已被标记为“质量非常低”,因此请改进。
【解决方案3】:

这是一个使用 Python 的答案。它为“rum”打印了正确的结果,但对于“rumm”它打印了两个“m”子字符串,原因很明显:

def substrings(s):
  result = []
  if len(s) == 0:
    result.append("")
  if len(s) > 0:
    result += substrings(s[1:])
  for n in range(1,len(s)+1):
    result.append(s[0:n])
  return result

print substrings("rum")

print substrings("rumm")

算法的思路如下:对于“rum”,子串是“um”后跟“r”、“ru”和“rum”的子串。对于“um”,子串是“m”后跟“u”和“um”的子串。对于“m”,子串是“”的子串后跟“m”。对于“”,子字符串只是“”。所以,最终的列表是“”、“m”、“u”、“um”、“r”、“ru”、“rum”。

虽然这不是 C++,但您应该能够将代码翻译成 C++。但这可能不一定是您想要的,因为“rumm”有两个“m”子字符串。如果您认为“rumm”应该只有一个“m”子字符串,请发表评论,我会发布另一个答案。

【讨论】:

  • 该问题已明确标记为 C++,因此您不应发布 python 代码,而应发布正确的算法。不能保证 OP 知道 python。
  • 你是对的。我现在在我对字符串“rum”的用例的回答中解释算法的想法。但是,我必须指出,Python 实际上是可执行的伪代码,通过使用 Python 回答,除了可以验证算法是否有效之外,我还可以轻松理解答案。
猜你喜欢
  • 2022-01-06
  • 1970-01-01
  • 2020-07-27
  • 1970-01-01
  • 2018-12-23
  • 2011-12-30
  • 2012-10-23
  • 2020-09-25
  • 1970-01-01
相关资源
最近更新 更多