題目描述:假設這有乙個各種字母組成的字串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,stringshortstring)
} 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,inthi)
}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次。
intmain()
;
//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 思路二 對兩個字串分別排序,同時依次輪...