簡體   English   中英

“按字母順序”排序(外星人字典代碼問題)

[英]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} 搜索深度可以增加。 我不確定這是一個好的解決方案。

我建議將問題視為有向圖:

  1. 首先遍歷單詞的有序列表並制作一個圖形: p->b->k and p->u->b and (duplicated) p->u
  2. 然后找到沒有傳入連接的節點(例如p )。 這將是字母表的第一個字符
  3. 然后迭代其傳出連接並找到除p外沒有傳入連接的節點。 這會給你第二個字符( u )。
  4. 然后遍歷第二個字符u的所有連接,找到除pu之外沒有其他傳入連接的節點。 那會給你b
  5. 等等等等

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM