使用ASCII值确定A是否是B的排列

时间:2016-04-24 03:12:24

标签: c++ c++11 permutation

我写了一个函数来确定字符串a是否是字符串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;
}

我的方法的问题是,如果a = 600000b = 111111,则函数返回true。

有什么方法可以保持我对这个问题的一般方法(而不是排序字符串然后做strcmp)并保持正确性?

3 个答案:

答案 0 :(得分:4)

如果您不需要UTF-8支持,这是一种简单的方法

这个问题的解决方案非常简单。处理此问题的标准库中有一个函数。

假设ab是两个string s:

return is_permutation(a.begin(), a.end(), b.begin(), b.end());

或者,如果您还无法访问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的上述答案,这在复杂性上是线性的。

指向is_permutation的文档的链接:http://en.cppreference.com/w/cpp/algorithm/is_permutation

指向sort的文档的链接: http://en.cppreference.com/w/cpp/algorithm/sort

如果需要UTF-8支持,则采用(小)更复杂的方法

以上可能在UTF-8字符串上失败。这里的问题是UTF-8是一种多字节字符编码,也就是说,单个字符可以用多个char变量编码。上面提到的方法都没有意识到这一点,并且都假设单个字符也是一个sigle char变量。两个UTF-8字符串的示例是这些方法失败的地方是:http://ideone.com/erfNmC

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

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);

然后,您可以在UTF-32编码的字符串上正确使用上述功能:

return is_permutation(a32.begin(), a32.end(), b32.begin(), b32.end()) << '\n';

或:

sort(a32.begin(), a32.end());
sort(b32.begin(), b32.end());
return (aa == bb);

缺点是现在John Zwinck的方法变得不那么实用了。您必须为1114112元素声明数组,因为这是实际存在多少个可能的Unicode字符。

有关转换为UTF-32的更多信息:http://en.cppreference.com/w/cpp/locale/wstring_convert/from_bytes

答案 1 :(得分:3)

您可以单独计算字符数:

module PaymentsHelper
  def invoices_for_payment_select(invoice)
    @invoices.collect { |i| ["#{i.client.name} - #{number_to_currency(i.outstanding)}", i.id] }
  end
end

答案 2 :(得分:0)

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() );