1. 程式人生 > >字串的包含問題簡單情況下的幾個演算法

字串的包含問題簡單情況下的幾個演算法

《程式設計之法》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);
}
程式碼不是很難,但是我寫了一下午……

看來還是太嫩了尷尬尷尬尷尬