《编程之法》Page5的问题
题目描述:给定一个长字符串a和段字符串b,a、b均不为空。请问,如何才能最快地判断出短字符串b中的所有字符是否在长串a中?编写bool StringContain(string &a,string &b)函数实现此功能。
书上列举了4中方法(书中还提到一种排序计数的方法),时间复杂度逐渐减小。这些方法分别是:(1)蛮力轮询(2)排序后轮询(3)素数相乘(4)位运算法
前面3种算法设计起来都没什么难度,下面我贴出我认为比较难想到的位运算法代码:
/*
对于只含26位大写字母的字符串A,我们可以只使用一个int型变量hash作为hash表,这是因为int变量有32bit。
若字符串A中含有字符A,则令变量hash的第1位置1,若字符串A中含有y,则令变量hash的第25位置1。
对于字符串B中任一字符,只需判断该字符在变量hash中所对应的位是否为1。
这样时间复杂度为O(m+n),空间复杂度为O(1)。
*/
#include <bitset>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
bool StringContain(string &a,string &b);
void BinaryBitset(int n) {
cout<<bitset<sizeof(int)*8>(n)<<endl;
}
void alphaPrint(){
char alpha[26];
cout<<"000000";
for(int i = 0; i < 26; i++)
{
alpha[i] = 'Z' - i;
cout<<alpha[i];
}
cout<<endl;
}
int main()
{
string a = "AKSJLKDPMN";
string b = "AKAB";
cout<<StringContain(a,b)<<endl;
return 0;
}
bool StringContain(string &a,string &b)
{
int hash = 0;
for( int i = 0; i < a.length(); ++i)
{
hash |= (1 << (a[i]-'A') ); //hash = hash | ( 1 << (a[i]-'A') ) hash或上1左移a[i]-'A'位,用0补位
}
cout<<"hash用2进制表示为:(对应的字符在下方 & 1 == true)\n";
BinaryBitset(hash);
alphaPrint();
for(int i = 0; i < b.length(); ++i)
{
if((hash & (1 << (b[i]-'A'))) == 0)
return false;
}
return true;
}
正如注释写的一样,这种方法很巧妙地用位运算符降低了求解难度……时间复杂度也较低。
就我个人而言,顶多想到这种方法:(1)将a中元素排序;(2)遍历b中元素,利用二分查找,寻找每个b中元素是否存在于a中
下午我实现了我个人的算法,源码如下:
//将a串排序之后,用b中的字符依次二分查找
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
bool StringContain(string &a,string &b);
int BSearch(char x, string &a, int begin, int end);
int main()
{
string a = "AKSJLKDJACBLSBJLAS";
string b = "ACE";
cout<<StringContain(a,b)<<endl;
system("PAUSE");
return 0;
}
bool StringContain(string &a,string &b)
{
sort(a.begin(),a.end()); //将a、b串预先排序
int aLength = a.size();
int bLength = b.size();
int result = -1;
for(int i = 0; i < bLength; i++)
{
result = BSearch(b[i],a,0,aLength);
if( result >= 0 && result <= aLength )
continue;
else
return false;
}
return true;
}
int BSearch(char x, string &a, int begin, int end)
{
if( begin >= end)
return -1;
int median = (begin+end)/2;
char y = a[median];
if( x == y )
return median;
else if( x > y )
return BSearch(x,a,median+1,end);
else
return BSearch(x,a,begin,median);
}
代码不是很难,但是我写了一下午……
看来还是太嫩了