【问题标题】:Recursively find a string within a string in C++在 C++ 中递归地在字符串中查找字符串
【发布时间】:2015-05-13 13:18:33
【问题描述】:

(C++) 给定 myString,我想检查 myString 是否包含子字符串。到目前为止,这是我所拥有的,但只有当字符串以子字符串开头时它才会返回 true。

 bool find(string myString, string substring)
{
    if(mystring.length() < substring.length())
    { 
        return false;
    }
    if(mystring == substring)
    {
        return true;
    }
    for(int i = 0; i < substring.length() - 1 ; ++i)
    {
        if(mystring.at(i) == substring.at(i))
           {
               continue;
           }
        else
        {
            string string2 = mystring.substr(1, mystring.length() - 1);
            return find(string2, substring); 
        }
        return true;
    }
    return false;
}

这个函数有什么问题?

【问题讨论】:

  • 虽然这样做很有趣,但您会获取大量字符串的值副本。您可以在没有单个字符串副本的情况下执行此操作,并且在 O(N) 中,即使您想搜索多个匹配项。
  • 我的意思是,为什么这个功能不起作用?
  • 我知道。我太老了,无法逐步执行此代码,但是 (i) substr 是从零开始的,并且 (ii) 你缺少 return
  • 当您递归检查子字符串比字符串少 1 个字符时,您只检查删除最左边字符的子字符串,而不检查删除最右边字符的其他可能子字符串。
  • 我该如何解决?我不认为你可以做双重递归......

标签: c++ string recursion substring


【解决方案1】:

检查此功能,它基于您的代码,删除额外代码并修复错误。

我还修改了签名来获取 const 引用以提高效率。

bool find(const string& myString, const string& substring)
{
    if(myString.length() < substring.length()){ 
        return false;
    }
    else if(myString.substr(0,substring.size()) == substring){
        return true;
    }
    else if (myString.length() > substring.length()){
        return find(myString.substr(1), substring); 
    }
    else{
        return false; 
    }
}

【讨论】:

  • 时间复杂度是多少?
【解决方案2】:

首先函数可以写得更简单。例如

bool find( const std::string &myString, const std::string &subString )
{
    return 
    ( myString.substr( 0, subString.size() ) == subString ) ||
    ( subString.size() < myString.size() && find( myString.substr( 1 ), subString ) );
}

这是一个演示程序

#include <iostream>
#include <iomanip>
#include <string>

bool find( const std::string &myString, const std::string &subString )
{
    return 
    ( myString.substr( 0, subString.size() ) == subString ) ||
    ( subString.size() < myString.size() && find( myString.substr( 1 ), subString ) );
}

int main()
{
    std::cout << std::boolalpha << find( "Hello World", "World" ) << std::endl;
    std::cout << std::boolalpha << find( "Hello C", "C++" ) << std::endl;
}   

程序输出是

true
false

至于你的函数,只有在两个字符串长度相同且彼此相等的情况下才会返回 true

if(myString == substring){
        return true;
    }

如果 myString.length() > substring.length() 函数什么也不返回

else if (myString.length() > substring.length()){
    int start = 1;
    int end = (int) myString.length() - 1;
    string string2 = myString.substr(start, end);
    find(string2, substring); 
}

我想你是说

    return find(string2, substring); 

在这段代码中sn-p。

编辑:我看到您在帖子中更改了函数的代码。但无论如何这段代码sn-p

for(int i = 0; i < substring.length() - 1 ; ++i)
{
    if(mystring.at(i) == substring.at(i))
       {
           continue;
       }
    else
    {
        string string2 = mystring.substr(1, mystring.length() - 1);
        return find(string2, substring); 
    }
    return true;
}

没有意义。

【讨论】:

  • 只是一个问题,我刚刚将您的答案选为“已回答”,但您为什么使用 size() 而不是 length()?为什么我一次迭代一个字符的更新函数不起作用?你很有帮助,我只是有些困惑。
  • @JCoder length 是 std::string 类成员函数大小的别名。所以它们可以互换使用。:) 我使用 size 是因为它更短。:)
  • @JCoder 至于你的第二个循环,那么循环的条件应该是 i
【解决方案3】:

在递归调用find 之前,您缺少return。就目前而言,它最终落入return false

另外,if (mystring == substring) 应该检查 mystring 是否以 substring 开头,而不是完全相等。

【讨论】:

  • 代码问题不止一个!已编辑。
【解决方案4】:

首先,由于 substr 中的内存副本,这很昂贵。

其次,你还没有检查子串长度 > 0。

第三,如果您已经完成了其他检查(包括子字符串长度 > 0),则对 mystring.length > 0 的“else if”检查是多余的。

现在到您的核心逻辑。在递归中,您的起点永远不会移动,因此您与起点联系在一起。您需要做的是从位置 1 开始,并在每次递归时递增 start,并使用 substr 提取从“start”到“start + substring.length”的子字符串。这样你就从头开始,继续前进,并检查正确的长度。您也可以从末尾开始(就像您一样)并向后移动,您需要做的是:找到 sart 位置(结束位置减去子字符串的长度),并在调用之前检查开始位置是否不小于零递归函数。

【讨论】:

    【解决方案5】:

    您只是删除了myString 最左边的字符,然后将其余字符与您的substring 进行比较。显然,当您的 substring 位于 myString 中间的某个位置时,这在一般情况下是行不通的。

    在每次迭代中,尝试比较的不是整个myString,而是它的第一个substring.size() 字符。这应该可以解决您的问题。

    【讨论】:

      【解决方案6】:

      这是我目前所拥有的,但它只在字符串返回 true 时 以子字符串开头。

      find("foo", "f") 也失败了。

      要查看原因,请在函数中添加一些测试输出:

      bool find(string myString, string substring)
      {
          std::cout << myString << ", " << substring << "\n";
          // ...
      }
      

      它将打印:

      foo, f
      oo, f
      o, f
      

      你明白为什么这行不通了吗?您只需继续删除第一个字符,直到仅将最后一个字符与要找到的子字符串进行比较。

      但即使find("foo", "o") 也失败了:

      foo, o
      oo, o
      o, o
      

      那是因为这条线:

         find(string2, substring); 
      

      您不会返回递归调用的结果。

      考虑到所有因素,我认为您只是在这里使用了错误的算法。它根本无法按照您编写代码的方式工作。

      其他一些观察:

          int start = 1;
          int end = (int) myString.length() - 1;
      

      那不是很好的风格。由于历史原因,std::string 的大小是无符号的,并且您正在使用 C 样式转换,而 static_cast 应该是首选。你应该在这里只使用std::string::size_type,因为它只是一段内部实现代码,你从转换为int 中没有任何收获。

         string string2 = myString.substr(start, end);
      

      substr 的第二个参数定义了子字符串的长度,而不是最后一个字符的索引。 end 听起来您使用该值作为最后一个字符的索引。看看http://en.cppreference.com/w/cpp/string/basic_string/substr

      【讨论】:

        猜你喜欢
        • 2016-10-02
        • 2014-05-16
        • 2014-03-23
        • 2022-06-23
        • 2014-02-19
        • 1970-01-01
        • 2021-12-10
        • 2021-09-20
        • 2012-11-16
        相关资源
        最近更新 更多