字串是否包含問題

2021-09-08 11:37:57 字數 4163 閱讀 6673

題目描述:

假設這有乙個各種字母組成的字串a,和另外乙個字串b,字串裡b的字母數相對少一些。什麼方法能最快的查出所有小字串b裡的字母在大字串a裡都有?

比如,如果是下面兩個字串:

string

1: abcdefghlmnopqrs

string

2: dcgsrqpo

答案是true,所有在string2裡的字母string1也都有。

如果是下面兩個字串:

string

1: abcdefghlmnopqrs

string

2: dcgsrqpz

答案是false,因為第二個字串裡的z字母不在第乙個字串裡。

文章源自:程式設計師程式設計藝術:第二章、字串是否包含問題

1)暴力輪詢

判斷string2中的字元是否在string1中?:

string 1: abcdefghlmnopqrs

string 2: dcgsrqpo

判斷乙個字串是否在另乙個字串中,最直觀也是最簡單的思路是,針對第二個字串string2中每乙個字元,一一與第乙個字串string1中每個字元依次輪詢比較,看它是否在第乙個字串string1中。

int comparestring(string longstring,string

shortstring)

} if (j==longstring.length())

} cout

<< "

true

"

1;

}

假設n是字串string1的長度,m是字串string2的長度,那麼此演算法,需要o(n*m)次操作,拿上面的例子來說,最壞的情況下將會有16*8 = 128次操作。顯然,時間開銷太大,我們需要找到一種更好的辦法。

2)排序方法

先對這兩個字串的字母進行排序,然後同時對兩個字串依次輪詢。兩個字串的排序需要(常規情況)o(m log m) + o(n log n)次操作,之後的線性掃瞄需要o(m+n)次操作

同樣拿上面的字串做例子,將會需要16*4 + 8*3 = 88,再加上對兩個字串線性掃瞄的16 + 8 = 24的操作。

int partition(string &str,int lo,int

hi)

}swap(str[i+1], str[hi]); //

不能改為swap(&data[i+1],&key)

return i + 1; }

//遞迴呼叫上述partition過程,完成排序。

void quicksort(string &str, int lo, int

hi)}

//比較,上述排序o(m log m) + o(n log n),加上下面的o(m+n),

//時間複雜度總計為:o(mlogm)+o(nlogn)+o(m+n)。

void compare(string str1,string

str2)

if (postwo ==str2.length())

cout

<< "

true

"

cout

<< "

false

"<}

3)計數排序

此方案與上述思路相比,就是在排序的時候採用線性時間的計數排序方法,排序o(n+m),線性掃瞄o(n+m),總計時間複雜度為:o(n+m)+o(n+m)=o(n+m)

void countersort(string str, string &help_str)

;

//help[index]存放了等於index + 'a'的元素個數

for (int i = 0; i < str.length(); i++)

//求出每個元素對應的最終位置

for (int j = 1; j < 26; j++)

help[j] += help[j-1

];

//把每個元素放到其對應的最終位置

for (int k = str.length() - 1; k >= 0; k--)

}//線性掃瞄o(n+m)

void compare(string long_str,string

short_str)

if (pos_short ==short_str.length())

cout

<< "

true

"

cout

<< "

false

"<}

4)hashtable的方法

把其中的每個字母都放入乙個hashtable裡(我們始終設m為短字串的長度,那麼此項操作成本是o(m)或8次操作)。然後輪詢長字串,在hashtable裡查詢短字串的每個字元,看能否找到。如果找不到,說明沒有匹配成功,輪詢長字串將消耗掉16次操作,這樣兩項操作加起來一共只有8+16=24次。

當然,理想情況是如果長字串的字首就為短字串,只需消耗8次操作,這樣總共只需8+8=16次。

int

main()

;

//num為輔助陣列中元素個數

int num = 0

;

//掃瞄短字串

for (int j = 0; j < str2.length(); j++)

}//掃瞄長字串

for (int k = 0; k < str1.length(); k++)

}//num為0說明長字串包含短字串內所有字元

if (num == 0

) cout

<< "

true

"

cout

<< "

false

"

}

5)o(n)到o(n+m)的素數方法

假設我們有乙個一定個數的字母組成字串,我給每個字母分配乙個素數,從2開始,往後類推。這樣a將會是2,b將會是3,c將會是5,等等。現在我遍歷第乙個字串,把每個字母代表的素數相乘。你最終會得到乙個很大的整數,對吧?

然後——輪詢第二個字串,用每個字母除它。如果除的結果有餘數,這說明有不匹配的字母。如果整個過程中沒有餘數,你應該知道它是第乙個字串恰好的子集了。

思路總結如下:

1.定義最小的26個素數分別與字元'a'到'z'對應。

2.遍歷長字串,求得每個字元對應素數的乘積。

3.遍歷短字串,判斷乘積能否被短字串中的字元對應的素數整除。

4.輸出結果。

至此,如上所述,上述演算法的時間複雜度為o(m+n),時間複雜度最好的情況為o(n)(遍歷短的字串的第乙個數,與長字串素數的乘積相除,即出現餘數,便可退出程式,返回false),n為長字串的長度,空間複雜度為o(1)。如你所見,我們已經優化到了最好的程度。

//

素數陣列

int primenumber[26] = ;

intmain()

//遍歷短字串

for (int j = 0; j < strtwo.length(); j++)

//如果積能整除短字串中所有字元則輸出"true",否則輸出"false"。

if (strtwo.length() ==j)

cout

<< "

true

"

cout

<< "

false

"

}

6)用32位整數中的低26位

bool acontainsb(char *a,char *b)   

while (*a)

} return

true

; }

字串是否包含問題

假設這有兩個分別由字母組成的字串a另外字串b,字串b的字母數較字串a少一些。什麼方法能最快地查出字串b所有字母是不是都在字串a裡?也就是說判斷字串b是不是字串a的真子集 為了簡化,姑且認為兩個集合都不是空集,即字串都不為空。解法一 暴力輪詢 就是將b中的每一字元都和a中的字元做對比,思想簡單此處就不...

演算法 字串是否包含問題

在網上看到這篇文章 一次谷歌面試趣事。覺得其中的演算法題以及作者的解決思路很有趣,就拿來分享一下吧。問題假設這有乙個各種字母組成的字串,假設這還有另外乙個字串,而且這個字串裡的字母數相對少一些。從演算法是講,什麼方法能最快的查出所有小字串裡的字母在大字串裡都有?比如,如果是下面兩個字串 string...

字串包含問題

字串包含問題 判斷小字串的所有字元是否大字串都有 思路一 針對小字串的每乙個字元一一與大字串的字元輪詢比較即可,很明顯時間複雜度為o n m bool compare string s1,string s2 if j s2.length return true 思路二 對兩個字串分別排序,同時依次輪...