在字符串中查找前缀

时间:2020-10-17 01:02:00

标签: c++ algorithm

我当前正在做一个leetcode问题,我必须在一个句子中找到一个前缀并返回该句子中的单词编号,否则返回-1。我想出了一个解决方案,但是它崩溃了一些字符串,我不知道为什么。以下是一个示例:

输入:句子=“我喜欢吃汉堡”,搜索字词=“汉堡”
输出:4(我也得到4的输出)
说明:“ burg”是句子中第4个单词“ burger”的前缀。

但此示例失败:

输入:句子=“这个问题很容易解决”,searchWord =“ pro”
输出:2(我得到6的输出)
说明:“ pro”是“ problem”的前缀,problem是句子中的第二个和第六个词,但是我们返回2,因为它是最小索引。

我为此的cout产生了一个非常奇怪的代码段:

 problem is an easy problem
 problem is an easy problem
 problem is an easy problem
 problem is an easy problem
probl
proble
problem
problem
problem i
problem is

当我增加时,它完全忽略了前几​​个子字符串,这是它唯一发生的时间。

int isPrefixOfWord(string sentence, string searchWord)
{
    string sub;
    int count = 1;
    for (int i = 0; i < sentence.length(); i++)
    {
        if (sentence[i] == ' ')
            count++;
        for (int j = i; j < sentence.length(); j++)
        {
            sub = sentence.substr(i, j);
            cout<<sub<<endl;
            if (sub == searchWord)
            {
                return count;
            }
        }
    }
    return -1;
}

有什么想法吗?

int isPrefixOfWord(string sentence, string searchWord)
{
    string sub;
    int count = 1;
    for (int i = 0; i < sentence.length() - searchWord.length() - 1; i++)
    {
        if (sentence[i] == ' ')
            count++;
        
        sub = sentence.substr(i,searchWord.length());
        if ( sub == searchWord && (sentence[i-1] == ' ' || i == 0))
        {
            return count;
        }
    
    }
    return -1;
}

3 个答案:

答案 0 :(得分:2)

影响函数输出的错误是您没有在内部for循环中处理i的增量:

for (int i = 0; i < sentence.length(); i++)
{
    if (sentence[i] == ' ')
        count++;

    for (int j = i; j < sentence.length(); j++)
    {
        sub = sentence.substr(i, j);
        cout<<sub<<endl;
        if (sub == searchWord)
        {
            return count;
        }
    }
}

请注意,一旦您的内循环完成,i总是会迭代一个。因此,您对单词的下一次搜索将错误地从其下一个字符开始,错误地搜索了“子单词”而不是前缀,因此会产生误报(和不必要的工作)。

还请注意,每次您这样做:

(sub == searchWord)

即使我们只对第j个新字符是否匹配感兴趣,这也会检查所有j个字符。

另一个错误,它会影响您的性能和cout,这是因为您没有处理不匹配的情况:

if (sub == searchWord)  

...从不虚假,因此退出内部循环的唯一方法是保持增量j到数组末尾,因此sub最终变得很大。


解决第二个错误的一种方法是像这样替换内部循环:

    if (sentence.substr(i, i + searchWord.length()) == searchWord)
        return count;

最后,修复所有错误:

int isPrefixOfWord (const string & sentence, const string & searchWord)
{
    if (sentence.length() < searchWord.length())
        return -1;

    const size_t i_max = sentence.length() - searchWord.length();

    for (size_t i = 0, count = 1; ; ++count)
    {
        // flush spaces:
        while (sentence[i] == ' ')
        {
            if (i >= i_max)
                  return -1;

            ++i;
        }

        if (sentence.substr(i, searchWord.length()) == searchWord)
            return count;
      
        // flush word:
        while (sentence[i] != ' ')
        {
            if (i >= i_max)
                  return -1;

            ++i;
        }
    }
  
    return -1;
}

请注意,substr提供了对象的副本(不仅仅是字符串的包装器),因此相对于searchWord.length(),这花费了线性时间,这在{{ 1}}较小。

我们可以通过替换来提高速度

sentence

...与

if (sentence.substr(i, searchWord.length()) == searchWord)
    return count;

其他人已经展示了可以解决问题的库的不错的应用程序。

如果您无权访问这些库进行分配,或者仅想学习如何在不降低效率的情况下模块化这样的问题,那么可以通过以下方法在 for (size_t j = 0; sentence[i] == searchWord[j]; ) { ++j; if (j == searchWord.size()) return count; ++i; } 中进行操作:任何库(c++11除外):

string

关于速度:如果我们认为bool IsSpace (char c) { return c == ' '; } bool NotSpace (char c) { return c != ' '; } class PrefixFind { using CharChecker = bool (*)(char); template <CharChecker Condition> void FlushWhile () { while ((m_index < sentence.size()) && Condition(sentence[m_index])) ++m_index; } void FlushWhiteSpaces () { FlushWhile<IsSpace>(); } void FlushToNextWord () { FlushWhile<NotSpace>(); FlushWhile<IsSpace>(); } bool PrefixMatch () { // SearchOngoing() must equal `true` size_t j = 0; while (sentence[m_index] == search_prefix[j]) { ++j; if (j == search_prefix.size()) return true; ++m_index; } return false; } bool SearchOngoing () const { return m_index + search_prefix.size() <= sentence.size(); } const std::string & sentence; const std::string & search_prefix; size_t m_index; public: PrefixFind (const std::string & s, const std::string & sw) : sentence(s), search_prefix(sw) {} int FirstMatchingWord () { const int NO_MATCHES = -1; if (!search_prefix.length()) return NO_MATCHES; m_index = 0; FlushWhiteSpaces(); for (int n = 1; SearchOngoing(); ++n) { if (PrefixMatch()) return n; FlushToNextWord(); } return NO_MATCHES; } }; 的长度为sentence,而m的长度为searchWord,则原始(越野车)代码具有n的时间复杂度。但是有了这项改进,我们得到了O(n*m^2)

答案 1 :(得分:2)

使用starts_with的非常简单的C++20解决方案:

#include <string>
#include <sstream>
#include <iostream>

int isPrefixOfWord(std::string sentence, std::string searchWord)
{
    int count = 1;
    std::istringstream strm(sentence);
    std::string word;
    while (strm >> word)
    {
        if ( word.starts_with(searchWord) )
           return count;
        ++count;
    }
    return -1;        
}

int main()
{
    std::cout << isPrefixOfWord("i love eating burger",  "burg") << "\n";
    std::cout << isPrefixOfWord("this problem is an easy problem", "pro") << "\n";
    std::cout << isPrefixOfWord("this problem is an easy problem", "lo");
}
    

输出:

4
2
-1

当前,LeetCode和许多其他在线编码站点不支持C ++ 20,因此此代码将无法在那些在线平台上成功编译。

因此,here is a live example using a C++20 compiler

答案 2 :(得分:0)

我们只能使用std::basic_stringstream解决此问题。这将通过:

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [TestModuleForAll],
    providers: []
  });
});
相关问题