cstring判断包含字符串_作为java程序员要知道的大厂常见的算法面试题:字符串的包含...
1.2 字符串的包含
題目描述
給定一長字符串a(chǎn)和一短字符串b。請問,如何最快地判斷出短字符串b中的所有字符是否都在長字符串a(chǎn)中?請編寫函數(shù)bool StringContain(string &a, string &b)實現(xiàn)此功能。
為簡單起見,假設輸入的字符串只包含大寫英文字母。下面舉幾個例子。
- 如果字符串a(chǎn)是"ABCD",字符串b是"BAD",答案是true,因為字符串b中的字母都在字符串a(chǎn)中,或者說b是a的真子集。
- 如果字符串a(chǎn)是"ABCD",字符串b是"BCE",答案是false,因為字符串b中的字母E不在字符串a(chǎn)中。
- 如果字符串a(chǎn)是"ABCD",字符串b是"AA",答案是true,因為字符串b中的字母A包含在字符串a(chǎn)中。
分析與解法
此題初看似乎很簡單,但要高效地實現(xiàn)并不輕松。而且,如果面試官步步緊逼,一個一個否決你想到的方法,要求你給出更快、更好的方案,恐怕就要費不少腦筋了。
解法一:蠻力輪詢
判斷短字符串b中的字符是否都在長字符串a(chǎn)中,最直觀也是最簡單的思路則是:輪詢短字符串b中的每一個字符,逐個與長字符串a(chǎn)中的每個字符進行比較,看是否都在字符串a(chǎn)中。
參考代碼如下:
bool StringContain(string &a, string &b) {for (int i = 0; i < b.length(); ++i){int j;for (j = 0; (j < a.length()) && (a[j] != b[i]); ++j);if (j >= a.length()){return false;}}return true; }如果n是長字符串a(chǎn)的長度,m是短字符串b的長度,那么此算法需要O(nm)次比較。顯然,如果n和m很大,時間開銷太大,需要尋找更好的辦法。
解法二:排序后輪詢
如果允許排序,可以考慮先排序后輪詢。例如,可先對這兩個字符串中的字母進行排序,然后再對兩個字符串依次輪詢。
常規(guī)情況下,兩個字符串的排序需要O(mlogm)+O(nlogn)次操作,之后的線性掃描需要O(m+n)次操作。關于排序方法,可以采用最常用的快速排序。
參考代碼如下:
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();){while ((pa < a.length()) && (a[pa] < b[pb])){++pa;}if ((pa >= a.length()) || (a[pa] > b[pb])){return false;}++pb;}return true; }解法三:素數(shù)相乘
有沒有比排序后輪詢更好的方法呢?
首先,讓長字符串a(chǎn)中的每個字母與一個素數(shù)對應,如A對應2,B對應3,C對應5,……,依次類推。再遍歷長字符串a(chǎn),把a中的每個字母對應的素數(shù)相乘,得到一個整數(shù)。然后,讓短字符串b中的字母也對應相應的素數(shù),再用b中的每個字母對應的素數(shù)除上面得到的整數(shù)。如果結果有余數(shù),說明結果為false,當即退出程序;如果整個過程中沒有余數(shù),則說明短字符串b是長字符串a(chǎn)的子集。
具體思路總結如下。
(1)按照從小到大的順序,用26個素數(shù)分別代替長字符串a(chǎn)中的所有字母。
(2)遍歷長字符串a(chǎn),求得a中的所有字母對應的素數(shù)的乘積。
(3)遍歷短字符串b,判斷上一步得到的乘積能否被b中的字母對應的素數(shù)整除。
(4)輸出結果。
上述算法的時間復雜度為O(m+n)。當然,最好情況下的時間復雜度為O(n),即在遍歷短字符串b的第一個字母,與長字符串a(chǎn)中所有字符所對應的素數(shù)的乘積相除時,當即出現(xiàn)余數(shù),便直接退出程序,返回false。
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 (int i = 0; i < a.length(); ++i){int x = p[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; }這種素數(shù)相乘的方法看似可行,實則不可行,因為素數(shù)相乘的結果會很大,從而導致整數(shù)溢出(前16個字母對應的素數(shù)相乘便會超出long long類型所能表示的最大整數(shù)范圍)。
解法四:位運算法
如果面試官繼續(xù)追問,到底有沒有更好的辦法呢?或許你絞盡腦汁能想到計數(shù)排序。但除了計數(shù)排序還有別的辦法嗎?
事實上,可以先把長字符串a(chǎn)中的所有字符都放入一個散列表(hash table)中,然后輪詢短字符串b,看b中的每個字符是否都在散列表里,如果都在,說明長字符串a(chǎn)包含短字符串b;否則,說明不包含。
再進一步,可以用位運算(26位整數(shù)表示)為長字符串a(chǎn)計算出一個“簽名”,再逐一將短字符串b中的字符放到a中進行查找。
參考代碼如下:
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'))) == 0){return false;}}return true; }這個位運算方法的實質是用一個整數(shù)代替了散列表,它的空間復雜度為O(1),時間復雜度為O(n+m)。至此,算是比較完美地解決了這個字符串包含的問題。
但是,這樣真的完美了嗎?請讀者繼續(xù)思考。
舉一反三
變位詞
如果兩個字符串中的字符一樣,出現(xiàn)次數(shù)也一樣,只是出現(xiàn)的順序不一樣,則認為這兩個字符串是兄弟字符串。例如,"bad"和"adb"即為兄弟字符串。現(xiàn)提供一個字符串,請問如何在字典中迅速找到它的兄弟字符串?
END
資料分享:
工作一到五年的程序員朋友面對目前的技術無從下手,感到很迷茫,高清思維導圖及相關視頻資料獲取方式關注+轉發(fā)+私信【架構】里面有阿里Java高級大牛直播講解知識點,分享知識,課程內容都是各位老師多年工作經(jīng)驗的梳理和總結,帶著大家全面、科學地建立自己的技術體系和技術認知!
精講直播課:
全面知識點分析:
豐富資料:
總結
以上是生活随笔為你收集整理的cstring判断包含字符串_作为java程序员要知道的大厂常见的算法面试题:字符串的包含...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python获取mac窗口坐标_[代码全
- 下一篇: 灯亮怎么办_车辆隔音效果不好怎么办?