【程式設計之法】如何最快的判斷出短字串b中的所有字元是否都在長字串a中?編寫函式bool StringContain(string&b,string&a)實現此功能。
阿新 • • 發佈:2019-02-13
舉例:
如果字串a是“ABCD”,字串b是“BAD”,答案是true.
如果字串a是“ABCD”,字串b是“BCE”,答案是false.
如果字串a是“ABCD”,字串b是“AA”,答案是true.
此處列舉四種方法:
解法一:蠻力輪詢
也是一般最容易想到的方法
bool StringContain(string &a, string &b)
{
for (int i = 0; i < b.length(); i++)
{
int j = 0;
for (j = 0; (j < b.length()) && (a[i] != a[j]); j++);
if (j >= a.length())
{
return false;
}
}
return true;
}
此演算法需要O(mn)比較
解法二:排序後輪詢
bool StringContain(string &a, string &b)
{
sort(a.begin(), a.end());
sort(b.begin(), b, end());
for (int pa = 0, pb = 0; pb < b.length(); pa++)
{
while ((pa < a.length()) && (a[pa] < b[pb]))
{
++pa;
}
if ((pa >= a.length()) || (a[pa]>b[pb]))
{
return false;
}
}
return true;
}
解法三:素數相乘
首先,讓字串a中的每個字母與一個素數對應,如A對應2,B對應3,C對應5,…,以此類推。再遍歷長字串a,把a中的每個字母對應的素數相乘,得到一個整數。然後,讓短字串b中的字母也對應相應的素數,再用b中的每個字母對應的素數除上面得到的整數。如果結果有餘數,說明結果為false,當即退出程式;如果整個過程沒有餘數,則說明短字串b是長字串的子集。
bool StringContain(string &a, string &b)
{
const int p[26] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101 };
int f = 1;
for (i = 0; i < a.length(); i++)
{
int x = pa[a[i] - 'A'];
if (f % x)
{
f *= x;
}
}
for (int i = 0; i < b.length(); i++)
{
int x = p[b[i] - 'A'];
if (f%x)
{
return false;
}
}
return true;
}
這種素數相乘的方法看似可行,實則不可行,因為素數相乘的結果很大,從而導致溢位,(前16個素數相乘便會超出long long 型別所表示的最大範圍)
解法四:位運算子
我們可以把長字串a中的所有字元都放入到一個散列表(hash table)中,然後輪詢短字串b,看b中的每個字元是否都放在散列表裡,如果都在,說明長字串a包含短字串b;否則,說明不包含。
bool StringContain(string &a, string &b)
{
int hash = 0;
for (int i = 0; i < a.length(); i++)
{
hash |= (1 << (a[i] - 'A'));
}
for (int i = 0; i < b.length(); i++)
{
if (!hash&(1 << (b[i] - 'A')))
{
return false;
}
}
return true;
}