【问题标题】:Checking if one string is a permutation of another in C++在 C++ 中检查一个字符串是否是另一个字符串的排列
【发布时间】:2016-06-07 02:50:51
【问题描述】:

我一直在研究一些编程问题,试图用数据结构和算法来刷新我的记忆。问题是检查一个字符串是否是另一个字符串的排列。

我见过的很多代码解决方案都会对每个字符串进行排序,然后检查排序后的字符串是否彼此相等。这通常通过执行以下操作来完成:

sort(strOne.begin(), strOne.end());
sort(strTwo.begin(), strTwo.end());

for (int i = 0; i < strOne.length(); i++) 
    {
        if (strOne[i] != strTwo[i]) 
        {
            return false; 
        }
    }

但是,我想知道在对字符串进行排序后,您是否可以直接比较字符串而不是使用 for 循环。例如,

     if (strOne == strTwo) {
    return true; 
 }

我是否遗漏了第二个选项不起作用的东西?我觉得我错过了一个基本概念,因为似乎大多数解决方案都有 for 循环来迭代字符串。

提前致谢!

【问题讨论】:

标签: c++ string algorithm


【解决方案1】:

您可以使用 str1.compare(str2) 按字典顺序比较字符串,如果相等则返回 0。

但是,您的解决方案需要 O(nlogn) 复杂度,并且可以在线性时间内解决...

【讨论】:

  • 推荐str1.compare(str2) != 0 超过str1 == str2 没有合理的理由;我只从缺乏运算符重载的语言的程序员那里看到过这样的建议。不过关于线性时间的要点:只需迭代第一个字符串 ++freq[s[i]],其中 freq 可以按字符值索引并默认为 0,然后是第二个字符串 --freq[s[i]],然后检查没有非零值。
  • (多想一想——假设你在前面return false 字符串长度不同,你可以使用if (--freq[s[i]] &lt; 0) return false; 提前纾困,然后就不需要决赛了在return true 之前检查非零)。
  • 如果str1.compare(str2)有效,那么std::set_symmetric_difference也应该有效pastebin.com/2i3quAQJ
【解决方案2】:

请在所有可能的条件下明确返回真或假。否则你可能得不到想要的结果。

在第一个代码块中,您没有在 for 循环之外定义返回值。 因此,明确地说,如果两个字符串相等,您的函数将不返回任何内容。

在第二个代码块中,您没有在 if 语句之外定义返回值。 因此,明确地,如果两个字符串不相等,您的函数将不返回任何内容。

【讨论】:

    【解决方案3】:
    std::sort( strOne.begin(), strOne.end() );
    std::sort( strTwo.begin(), strTwo.end() );    
    return strOne == strTwo;
    

    足够了。


    我的建议是使用std::unordered_map

    std::unordered_map< char, unsigned > umapOne;
    std::unordered_map< char, unsigned > umapTwo;
    for( char c : strOne ) ++umapOne[c];
    for( char c : strTwo ) ++umapTwo[c];
    return umapOne == umapTwo;
    

    作为一种优化,您可以在解决方案的顶部添加

    if( strOne.size() != strTwo.size() ) return false;
    

    更好的std::unordered_map解决方案,

    if( strOne.size() != strTwo.size() ) return false; // required
    std::unordered_map< char, int > umap;
    for( char c : strOne ) ++umap[c];
    for( char c : strTwo ) if( --umap[c] < 0 )  return false;
    return true;
    

    如果你只需要解决一个问题而不知道怎么做,你可以使用std::is_permutation

    return std::is_permutation( strOne.begin(), strOne.end(), strTwo.begin(), strTwo.end() );
    

    【讨论】:

      【解决方案4】:

      只是为了补充其他答案,如果您先验地知道两个字符串的字符范围('a' - 'z')或类似的东西,那么您可以在线性时间内解决问题。这个问题在 O(n log n) 内解决可能没问题,但情况并非总是如此。

      这将是我解决此问题的版本。它使用的事实是,如果两个词对每个字符的频率相等,则可以将一个词重新排列到另一个词中。

      #include <string>
      #include <vector>
      #include <map>
      #include <iostream>
      
      using namespace std;
      
      int main()
      {
          string a, b;
          cin >> a >> b;
          vector<int> frequencyOfLettersA(26, 0);
          vector<int> frequencyOfLettersB(26, 0);
      
          for(char c : a)
              frequencyOfLettersA[c - 'a']++;
          for(char c : b)
              frequencyOfLettersB[c - 'a']++; 
      
          bool isPermutation = true;
          for(int i = 0; i < 26; ++i)
          {
              if(frequencyOfLettersA[i] != frequencyOfLettersB[i])
              {
                  isPermutation = false;
                  break;
              }
          }
          if(isPermutation)
              cout << "Yes" << endl;
          else
              cout << "No" << endl;
      }
      

      【讨论】:

        【解决方案5】:

        STL方式是:

        std::string str0, str1;
        bool IsPermutation = std::is_permutation(str0.begin(), str0.end(), str1.begin(), str1.end());
        

        【讨论】:

          【解决方案6】:

          是的,你可以直接比较字符串。在函数中使用字符串比较的正确方法是

           return str1 == str2;
          

          环岛路

           if (str1 == str2) {
               return true;
           }
           else {
               return false;
           }
          

          有主要缺点:它要长几倍,很容易忘记else 部分(您刚刚做过),并且在重构期间更容易中断。

          【讨论】:

            猜你喜欢
            • 2011-02-07
            • 2019-05-11
            • 2022-07-01
            • 2019-04-17
            • 1970-01-01
            • 2011-12-16
            • 2013-05-12
            • 1970-01-01
            相关资源
            最近更新 更多