一道筆試編程題,想出一個時空複雜度O(N*L)的方法,不知道有沒有更快的 。
題目描述:現給出N個長度爲L的單詞。單詞中僅包含大寫英文字母(A-Z)。
1<=N<=2000
1<=L<=10
你可以從這些單詞中的第n個字母中挑一個作爲你拼詞的第n個字母
比如給出N=3個L=4的單詞:
CAKE
TORN
SHOW
你可以(但不僅限於)拼出以下單詞:
CORN
SAKE
CHRE
但不能拼出:
KARE
因爲N個單詞中,沒有首字母爲K的。
問:按照上述規則,拼出一個與這N個單詞都不相同的新單詞。若無法拼出,則輸出“-”。若有超過一個符合條件的單詞,則輸出字典序最小的那個單詞。
輸入描述:第一行包含2個正整數N、L,分別表示單詞數量與每個單詞長度。
接下來有N行,每行包含一個長度爲L的字符串,字符串中僅包含大與英文字母。這N個字符串表示給出的N個單詞
輸出描述:
輸出佔一行,僅包含一個字符串,表示題目要求的單詞,若找不到這樣的單詞,則按題目表述出“-”。
#include <iostream>
#include <string>
#include <unordered_set>
#include <vector>
using namespace std;
void moveNext(const vector<bool>&build, char ¤t) {//O(1)
current++;
while (current-'A' < build.size()
&& build[current-'A'] == false) {
current++;
}
}
int englishWord() {
int N, L;
while (cin >> N >> L) {
unordered_set<string> words;
for (int i = 0; i < N; ++i) {//O(N),保存N個長度爲L的字符串
string w;
cin >> w;
words.emplace(std::move(w));
}
//保存每個位置出現過的字母,這樣可以鎖定爲26,且不用考慮排序,用std::set<char>也可以
vector<vector<bool>> exist(L, vector<bool>(26, false));
vector<char> firstKey(L,'Z'+1);//保存每個位置出現的字典序最小的字母
for (auto& s : words) {//時間複雜度O(N*L)
for (int i = 0; i < L; ++i) {
exist[i][s[i] - 'A'] = true;
if (s[i]< firstKey[i])
firstKey[i] = s[i];
}
}
string res(L, '\0');
for (int i = 0; i < L; ++i) {//O(L),生成第一個答案
res[i] = firstKey[i];
}
//檢查是否重複,並且自加、進位
while (words.find(res) != words.end()) {//O(L)
int pos = L - 1;
moveNext(exist[pos], res[pos]);//從最後一位開始自加
while (pos > 0 && res[pos] == 'Z' + 1) {//逐位判斷是否需要進位
res[pos] = firstKey[pos];
moveNext(exist[pos - 1], res[pos - 1]);
pos--;
}
if (pos == 0 && res[pos] == 'Z' + 1) {//找完了,全都不符合
res = "-";
break;
}
}
cout << res;
}
return 0;
}
題給測試用例
3 4
COKE
TARN
SHOW
輸出CAKE,通過
自己的例子
3 5
AAAAA
AAAAB
AAAAC
輸出-,通過
5 5
AAAAA
AAAAB
AAAAC
ABCDE
BBBBF
輸出AAAAE,通過
7 5
AAAAA
AAAAB
AAAAC
AAABA
AAABB
AAABC
AABAA
輸出AABAB,通過
9 3
AAA
AAB
AAC
ABA
ABB
ABC
ACA
ACB
ACC
輸出-,通過
歡迎打臉