C++ 使用ASCII值确定A是否是B的置换

C++ 使用ASCII值确定A是否是B的置换,c++,c++11,permutation,C++,C++11,Permutation,我编写了一个函数来确定stringa是否是stringb的排列。定义如下: bool isPermutation(std::string a, std::string b){ if(a.length() != b.length()) return false; int a_sum, b_sum; a_sum = b_sum = 0; for(int i = 0; i < a.length(); ++i){ a_sum += a

我编写了一个函数来确定string
a
是否是string
b
的排列。定义如下:

bool isPermutation(std::string a, std::string b){
    if(a.length() != b.length())
        return false;
    int a_sum, b_sum;
    a_sum = b_sum = 0;
    for(int i = 0; i < a.length(); ++i){
        a_sum += a.at(i);
        b_sum += b.at(i);
    }
    return a_sum == b_sum;
}
bool isPermutation(std::string a,std::string b){
如果(a.长度()!=b.长度())
返回false;
int a_和,b_和;
a_sum=b_sum=0;
对于(int i=0;i
我的方法的问题是,如果
a=600000
b=111111
,函数将返回true


有什么方法可以让我保持解决这个问题的常规方法(而不是先对字符串进行排序,然后再执行strcmp)并保持正确性吗?

您可以分别计算字符数:

bool isPermutation(std::string a, std::string b)
{
    if(a.length() != b.length())
        return false;

    assert(a.length() <= INT_MAX);
    assert(b.length() <= INT_MAX);

    int counts[256] = {};
    for (unsigned char ch : a)
        ++counts[ch];
    for (unsigned char ch : b)
        --counts[ch];
    for (int count : counts)
        if (count)
            return false;

    return true;
}
bool isPermutation(std::string a,std::string b)
{
如果(a.长度()!=b.长度())
返回false;
如果不需要UTF-8支持,assert(a.length()是一种简单的方法
这个问题的解决方法非常简单,标准库中有一个函数可以处理这个问题

假设
a
b
是两个
string
s:

return is_permutation(a.begin(), a.end(), b.begin(), b.end());
u32string a32 = wstring_convert<codecvt_utf8<char32_t>, char32_t>{}.from_bytes(a);
u32string b32 = wstring_convert<codecvt_utf8<char32_t>, char32_t>{}.from_bytes(b);
或者,如果您还没有访问C++14的权限:

return a.size() == b.size() && is_permutation(a.begin(), a.end(), b.begin());
请注意,虽然这一点的复杂性只能保证不比字符串大小的二次方差。因此,如果这很重要,对两个字符串进行排序确实是一个更好的解决方案:

string aa(a); sort(aa.begin(), aa.end());
string bb(b); sort(bb.begin(), bb.end());
return (aa == bb);
如果这也会减慢速度,请使用上面John Zwinck的答案,它的复杂性是线性的

链接到
的文档是_permutation

链接到排序的文档

如果需要UTF-8支持,则采用(稍微)更复杂的方法 上述方法在UTF-8字符串上可能会失败。这里的问题是UTF-8是一种多字节字符编码,也就是说,一个字符可以在多个
char
变量中编码。上面提到的方法都没有意识到这一点,并且都假设一个字符也是一个单字节
char
变量。两个UT的示例如果这些方法失败,F-8字符串如下:

解决方案可能是将我们的UTF-8字符串临时复制到一个固定长度的UTF-32编码字符串。假设
a
b
是两个UTF-8编码的
string
s:

return is_permutation(a.begin(), a.end(), b.begin(), b.end());
u32string a32 = wstring_convert<codecvt_utf8<char32_t>, char32_t>{}.from_bytes(a);
u32string b32 = wstring_convert<codecvt_utf8<char32_t>, char32_t>{}.from_bytes(b);
缺点是,现在John Zwinck的方法变得不太实用了。您必须声明1114112个元素的数组,因为这是实际存在的可能的Unicode字符数

有关转换为UTF-32的更多信息:

这就足够了


我的建议是使用
std::unordered_map

i、 e


更好的
std::无序地图
解决方案

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;

如何在字符串中添加字符?这些字符不应该使用静态类型转换或其他方法转换为int吗?可能是atoi()“MikeNickaloff感谢你的评论。我把字符的ASCII值加起来,C++不需要我明确地把它显示出来。我希望我的例子是<代码> A= 600000 和<代码> B=111111 < /COD>不会把你甩掉,我也在谈论他们的ASCII值,而不是它们的整数值!@好吧,我删除了我的答案。因为它在这种情况下并不真正适用。@MikeNickaloff问题不在于OP在字符串中添加字符。问题在于算法是错误的。计算两个范围中的值之和并不能检查一个范围是否是另一个范围的排列。我想知道如果字符串包含UTF-8 c,这个问题的所有答案是否都不会失败字符。谢谢你的回答。我只想澄清一下,由于扩展的ASCII假设,
计数
的大小是否为256。另外,为什么将
ch
声明为
无符号字符
?@ishyfishy
为什么将ch声明为无符号字符?
字符串
包含
字符
值,并且这些值可以是负数。如果你不这样做的话将它们转换为无符号类型,这样在理论上,当您编写
counts[ch]时,您可能会冒用负值索引数组的风险
@JohnZwinck为什么不使用
string::size\u type
?@gaazkam我完全不知道char值可以是负数!不过现在这很有意义了。@gaazkam:我应该在哪里使用
string::size\u type
?而不是
int
?我发现如果签名,缓存行为会更直观。另外,使用
int
。如果您愿意的话如果字符串的大小超过2GB,请使用
ssize\u t
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;
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;
return std::is_permutation( strOne.begin(), strOne.end(), strTwo.begin(), strTwo.end() );