[英]Sorting 'Alphabetically' (Alien Dictionary Code Problem)
我已經開始解決編碼問題以嘗試提高我的技能。
我正在研究“外星人詞典”編碼問題,當給定“外星詞”的排序列表時,您需要確定“外星人字母”。 外星人字母表由拉丁字符組成,但順序與我們的不同。
從那以后,我了解到有更優化的方法來解決這個問題,我將研究這些方法,但我希望看到我的本能方法一直到完成。
我的代碼確實使用 c++20 編譯並輸出正確的字母,但是,我必須實現一個“hack”來覆蓋我在代碼注釋中解釋的邊緣情況。
我無法完全理解為什么我需要這個 hack,或者如何修復我的代碼而不需要它。
#include <iostream> // std::cout
#include <map> // std::map
#include <vector> // std::vector
#include <algorithm> // std::sort
/*
Input: words[] = ["pbb", "bpku", "bpkb", "kbp", "kbu"];
Expected Output: ['p', 'u', 'b', 'k'];
*/
typedef std::vector<std::string> WordList;
WordList alienWords = {"pbb", "bpku", "bpkb", "kbp", "kbu"};
typedef std::map<std::pair<char, char>, char> RuleBook;
RuleBook alienRuleBook;
typedef std::vector<char> Alphabet;
Alphabet alienAlphabet;
void populateAlphabet(Alphabet& alphabet, WordList& wordList) {
alphabet.clear();
for (int word = 0; word < wordList.size(); word++) {
for (int letter = 0; letter < wordList[word].size(); letter++) {
if(std::find(alphabet.begin(), alphabet.end(), wordList[word][letter]) == alphabet.end()) {
alphabet.push_back(wordList[word][letter]);
}
}
}
}
void generateRules(RuleBook& ruleBook, WordList& wordList){
for (int firstWord = 0; firstWord < wordList.size(); firstWord++) {
for (int secondWord = firstWord + 1; secondWord < wordList.size(); secondWord++) {
if (secondWord == wordList.size()) break;
int letter = 0;
for (; letter < wordList[firstWord].size(); letter++) {
if (wordList[firstWord][letter] == wordList[secondWord][letter]) continue;
ruleBook[{wordList[firstWord][letter], wordList[secondWord][letter]}] = '<';
ruleBook[{wordList[secondWord][letter], wordList[firstWord][letter]}] = '>';
break;
}
}
}
}
// needs to return TRUE if 'l' should come before 'r'.
bool getRule(char l, char r) {
switch(alienRuleBook[{l, r}]) {
case '>': return false;
case '<': return true;
}
std::cout << "ERROR! No rule found for: '" << l << "' vs '" << r << "'\n\n";
// The below is a hack because I don't understand to fix the case of {'u', 'k'}
// There's no 'discovered' rule saying 'u' comes before 'k' or 'k' comes after 'u'
// even though we KNOW 'u' comes before 'b' and we know that 'b' comes before 'k'.
return true;
}
void printAlphabet(Alphabet& alphabet){
std::cout << "=== Alphabet ===" << "\n ";
for(const auto it : alphabet)
std::cout << it << " ";
std::cout << "\n================\n\n";
}
void printRuleBook(RuleBook& ruleBook){
std::cout << "=== Discovered Rules ===" << "\n";
for(const auto it : ruleBook)
std::cout << " " << it.first.first << " " << it.second << " " << it.first.second << '\n';
std::cout << "================\n\n";
}
int main() {
populateAlphabet(alienAlphabet, alienWords);
generateRules(alienRuleBook, alienWords);
std::sort(alienAlphabet.begin(), alienAlphabet.end(), getRule);
printRuleBook(alienRuleBook);
printAlphabet(alienAlphabet);
return 0;
}
為了實現getRule
function 如果沒有{a, b}
隱式規則,您應該搜索{a, x} = '>'
其中{x, b} = '>'
或{a, x} = '<'
其中{x, b} = '<'
// in case if a > b, you search for "a > x and x > b".
// In other words, if a is greater than x and x is greater than b,
// then a is greater than b.
a ... x ... b
// the similar is for case when a < b
b ... x ... a
如果找不到{a, x} and {x, b}
,則應搜索{a, x} + {x, y} + {y, b}
。 搜索深度可以增加。 我不確定這是一個好的解決方案。
我建議將問題視為有向圖:
p->b->k
and p->u->b
and (duplicated) p->u
p
)。 這將是字母表的第一個字符p
外沒有傳入連接的節點。 這會給你第二個字符( u
)。u
的所有連接,找到除p
和u
之外沒有其他傳入連接的節點。 那會給你b
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.