給定一個大小為 K 個字母的集合和字串 S,求出在使用該集合所組出長度為 L 字串中,不為字串 S 子字串的最小字典序字串為何。
例如字母集合 {a, c, m},其能組出長度為 2 的字串字典序由小到大排序為 aa < ac < am < ca < cc < cm < ma < mc < mm。字串 S 為「accaamcm」,因此 ma 為不在 S 內的最小字典序字串。
範例測資
範例輸入 | 範例輸出 |
---|---|
第一行為一個長度為 K (1 <= K <= 10) 的小寫字母字串代表字母集合,保證字元不重複且照字元由小到大排序。 第二行為一個正整數 L (1 <= L <= 8,1 <= KL <= 6*105)。 第三行為小寫英文字串 S (L <= |S| <= 5*105)。 | 輸出滿足題目要求的最小字典序字串。 |
acm 2 accaamcm | ma |
dp 3 dddppdpd | pdd |
解題思路
使用 DFS 去將所有組合計算出來,因為可以有重複的字元,所以 DFS 的參數只需要目前相加的字串。宣告一個 Map 來紀錄有哪些組合,這邊取名叫做 MAP,當 DFS 中的字串長度 == L 時,將 MAP[字串]++ 並且 return。
跑一個 For迴圈 從 0 到 S.length()-L,並且宣告另外一個 Map 來紀錄 S 中長度為 L 的子字串有哪些,這邊取名叫 appear。在裡面再跑一個 For迴圈 從目前的 i 到 i+L,要從目前的位置加字串加到 L 的長度。加完之後將 appear[剛剛加完的字串]++。
之後跑一個 for (auto it:MAP),要將剛剛 K 中的所有組合做判斷,如果 appear[it.first] == 0,代表 S 中沒有這個子字串,但是剛剛的 DFS 有計算出這個 it.first,這個就是答案,輸出 it.first 之後將迴圈 break。跑 for (auto it:MAP) 的時候會依照字串的順序跑,所以先跑到的就會是較小的字典序字串。
範例程式碼-ZeroJudge O078: 缺字問題
#include <iostream>
#include <map>
using namespace std;
string K, str;
int L;
map<string, int>MAP;
void DFS(string add) {
if (add.length() == L) {
MAP[add]++;
return;
}
for (int i = 0; i<K.length(); i++) DFS(add+K[i]);
}
int main() {
cin.sync_with_stdio(0);
cin.tie(0);
cin >> K >> L >> str;
DFS("");
map<string, int>appear;
for (int i = 0; i<=str.length()-L; i++) {
string tmp = "";
for (int j = i; j<i+L; j++) tmp += str[j];
appear[tmp]++;
}
for (auto it:MAP) {
if (appear[it.first] == 0) {
cout << it.first << "\n";
break;
}
}
}
//ZeroJudge O078
//Dr. SeanXD