在 C++ 中检查一个字符串是不是是另一个字符串的排列

Posted

技术标签:

【中文标题】在 C++ 中检查一个字符串是不是是另一个字符串的排列【英文标题】: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 循环来迭代字符串。

提前致谢!

【问题讨论】:

std::is_permutation。就用它吧。或者如果你想知道它是如何工作的,你可以阅读它的代码。 link 示例...... ***.com/questions/36818877/… 【参考方案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 部分(您刚刚做过),并且在重构期间更容易中断。

【讨论】:

以上是关于在 C++ 中检查一个字符串是不是是另一个字符串的排列的主要内容,如果未能解决你的问题,请参考以下文章

如何检查一个字符串“StartsWith”是不是是另一个字符串?

检查一个字符串是不是是另一个字符串的前缀

如何在不使用大型结果集的情况下检查一个字符串是不是是另一个字符串的子字符串?

如何检查字符串中的数据是不是是 C++ 上的数字?

C++ 检查字符串是不是包含至少 1 个数字和 1 个字母

检查字符串是不是是名称的可能缩写