1. 程式人生 > >【程式設計之法】如何最快的判斷出短字串b中的所有字元是否都在長字串a中?編寫函式bool StringContain(string&b,string&a)實現此功能。

【程式設計之法】如何最快的判斷出短字串b中的所有字元是否都在長字串a中?編寫函式bool StringContain(string&b,string&a)實現此功能。

舉例:
如果字串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;
}