題目描述:
假設這有乙個各種字母組成的字串a,和另外乙個字串b,字串裡b的字母數相對少一些。什麼方法能最快的查出所有小字串b裡的字母在大字串a裡都有?
比如,如果是下面兩個字串:
string 1: abcdefghlmnopqrs
string 2: dcgsrqpo
答案是true,所有在string2裡的字母string1也都有。
如果是下面兩個字串:
string 1:abcdefghlmnopqrs
string 2: dcgsrqpz
答案是false,因為第二個字串裡的z字母不在第乙個字串裡。
1:o(n*m)的輪詢方法
判斷乙個字串是否在另乙個字串中,最直觀也是最簡單的思路是,針對第二個字串string2中每乙個字元,一一與第乙個字串string1中每個字元依次輪詢比較,看它是否在第乙個字串string1中。**如下:
int comparestring(string longstring, string shortstring)
}
if (j == longstring.length())
}
cout << "true" <
return 1;
}2:o(mlogm)+o(nlogn)+o(m+n)的排序方法
乙個稍微好一點的方案是先對這兩個字串的字母進行排序,然後同時對兩個字串依次輪詢。兩個字串的排序需要(採用最常用的快速排序)o(m log m) + o(n log n)次操作,之後的線性掃瞄需要o(m+n)次操作。**如下:
void compare(string str1, string str2)
//str1 is longstring, str2 is shortstring
if (postwo == str2.length())
cout << "true" <
else
cout << "false"<< endl;
}3:o(n+m)的計數排序方法
同樣是先排序,後比較的演算法,因為需要排序的元素為26個字母,所以,可以採用線性時間的排序演算法,比如計數排序,這樣,需要的時間為:o(n) + o(m) +o(n+m) = o(n+m)。**不再贅述。
4:o(n+m)的hashtable的方法
可以對短字串進行輪詢(最好是應該把短的先儲存,那樣,會降低題目的時間複雜度),把其中的每個字母都放入乙個hashtable裡。然後輪詢長字串,具體演算法如下:
a、hash[26],先全部清零,然後掃瞄短的字串,若有相應的置1,
b、計算hash[26]中1的個數,記為m
c、掃瞄長字串的每個字元a;若原來hash[a] == 1 ,則修改hash[a]= 0,並將m減1;若hash[a] == 0,則不做處理
d、若m == 0 or 掃瞄結束,退出迴圈。
**如下:
int hash[26] = ;
// 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" <
else
cout << "false"<< endl;
5: o(n+m)的素數方法
給每個字母分配乙個素數,從2開始,往後類推。這樣a將會是2,b將會是3,c將會是5,等等。具體思路如下:
a.定義最小
的26個素數分別與字元'a'到'z'對應。
b.遍歷長字串,求得每個字元對應素數的乘積。
c.遍歷短字串,判斷乘積能否被短字串中的字元對應的素數整除。
d.輸出結果。
上述演算法的時間複雜度為o(m+n),空間複雜度為o(1)。該演算法提供的「是一種更、更、更有趣的方案。」,**如下:
int primenumber[26] = ;
int main()
// 遍歷短字串
for (int j = 0; j< strtwo.length(); j++)
// 如果積能整除短字串中所有字元則輸出"true",否則輸出"false"。
if (strtwo.length() == j)
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}6:bit-map方法
所謂的bit-map就是用乙個bit位來標記某個元素對應的value,而key即是該元素。由於採用了bit為單位來儲存資料,因此在儲存空間方面,可以大大節省。
先舉幾個bit-map的用例:
a:排序:
#define bytesize 8
//將位陣列p的第posi位置為1
void setbit(char *p, int posi)
*p =*p|(0x01<<(posi%bytesize)); //
將該bit
位賦值1
return;
}
void bitmapsortdemo()
;
//bufferlen這個值是根據待排序的資料中最大值確定的
//待排序中的最大值是14,因此只需要2個bytes(16個bit)
//就可以了。
const int bufferlen= 2;
char *pbuffer = new char[bufferlen];
//要將所有的bit位置為0,否則結果不可預知。
memset(pbuffer, 0, bufferlen);
for(int i=0; i<9; i++)
//輸出排序結果
for(i=0; i
}
pbuffer++;
} printf("\n");
}
b:已知某個檔案內包含一些**號碼,每個號碼為8位數字,統計不同號碼的個數。
8位最多99 999 999,大概需要99m個bit,大概10幾m位元組的記憶體即可。
c:2.5億個整數中找出不重複的整數的個數,記憶體空間不足以容納這2.5億個整數。
將 bit-map擴充套件一下,用2bit表示乙個數即可,0表示未出現,1表示出現一次,2表示出現2次及以上,在遍歷這些數的時候,如果對應位置的值是0, 則將其置為1;如果是1,將其置為2;如果是2,則保持不變。
利用bit-map解決字串是否包含問題的思路是:每個字母的ascii碼值,可以對應乙個點陣圖中的位。先遍歷第乙個長字串,生成乙個「位圖字典」。 然後,遍歷第二個短字串,用查字典的方式較檢即可。演算法時間複雜度為o(m+n),空間複雜度為o(1)。**如下:
#define getbit(x) (1<<(x-'a'))
void a_has_b(char * a, char * b)
if(i == blen)
printf("yes! a hasb!/n");
else
printf("no! char at %d is not found indictionary!/n",i);
} 該演算法與hashtable演算法的本質相同,只是形式不一樣而已。
7:字串匹配問題
題目描述:
假設兩個字串中所含有的字元和個數都相同我們就叫這兩個字串匹配,比如:abcda和adabc,由於出現的字元個數都是相同,只是順序不同,所以這兩個字串是匹配的。
要求高效實現下面的函式: boolenis_match(char *str1,char *str2)。
分析:可以看出,此字串的匹配問題,是與上述字串包含的問題相類似的,這個問題可以先排序再比較,也可以利用hash表進行判斷。這裡給出一種hash表的方法,原理已在上文中闡明了,**如下:
bool is_match(const char *strone, const char *strtwo)
; // 掃瞄字串
for (int i = 0; i < strlen(strone); i++)
// 掃瞄字串
for (int j = 0; j < strlen(strtwo); j++)
return true;
}
19 字串移位包含問題
總時間限制 1000ms 記憶體限制 65536kb 描述對於乙個字串來說,定義一次迴圈移位操作為 將字串的第乙個字元移動到末尾形成新的字串。給定兩個字串s1和s2,要求判定其中乙個字串是否是另一字串通過若干次迴圈移位後的新字串的子串。例如cdaa是由aabcd兩次移位後產生的新串bcdaa的子串,...
002字串包含
2014.6.17 題目描述 給定兩個分別由字母組成的字串a和字串b,字串b的長度比字串a短。請問,如何最快地判斷字串b中所有字母是否都在字串a裡?為了簡單起見,我們規定輸入的字串只包含大寫英文本母,請實現函式bool stringcontains string a,string b 比如,如果是下...
t2712 字串移位包含問題
t2712 字串移位包含問題 總時間限制 1000ms 記憶體限制 65536kb 描述給定兩個字串s1和s2,要求判定其中乙個字串 是否是另一字串通過迴圈移位後的子字串。例如 cdaa是由aabcd兩次移位後bcdaa的子串,而abcd 與acbd不能通過移位來得到其中乙個字串是另乙個字 符串迴圈...