问题:“由各种字母组成的字符串S,另外一个字母数相对少一些的字符串T,设法最快的查出是否T中的字母均在S中?”
思路:
判断集合A是否包含集合B,即判断其差(A-B)是否为空集。(A-B)不好算,可换为求(A -(A交B))。
考虑集合的表示方面,没要求顺序,即无序集。
仅考虑26个小写字母的情况,自然地想用位向量。用32位整数表示集合,第0位为1表示含'a',第1位为1表示含'b',……
#include <cassert>
#include <iostream>
using namespace std;
/*
这个示意性的程序仅考虑了26个小写字母。
若字符集更大可换用数组作为字符串的“签名”,对UNICODE,0x10FFFF个字符用int[]不过4M内存,也可继续按位存储省点内存。
*/
int str_sig(char const *ps)
{
assert(ps);
assert(isalpha(*ps));
int sig = 0;
while(*ps){
sig |= (1 << (*ps - 'a'));
++ps;
}
return sig;
}
bool contains_charset(char const *psa, char const *psb)
{
int sig_a = str_sig(psa);
int sig_b = str_sig(psb);
return ((sig_a & sig_b) ^ sig_b) == 0;
}
void test(char const *psa, char const *psb)
{
cout << "\"" << psa << "\" " << (contains_charset(psa, psb) ? "" : "not ") << " contains \"" << psb << "\"\n";
}
int main()
{
assert(str_sig("") == 0);
assert(str_sig("a") == (1 << 0));
assert(str_sig("z") == (1 << 25));
assert(str_sig("abcdefghijklmnopqrstuvwxyz") == ((1 << 26) - 1));
test("", "");
test("a", "a");
test("a", "b");
test("ab", "b");
test("bc", "b");
test("abc", "b");
test("abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
return 0;
}