[LeetCode] Alien Dictionary 另类字典

简介:

There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you. You receive a list of words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language.

For example,
Given the following words in dictionary,

[
  "wrt",
  "wrf",
  "er",
  "ett",
  "rftt"
]

The correct order is: "wertf".

Note:

  1. You may assume all letters are in lowercase.
  2. If the order is invalid, return an empty string.
  3. There may be multiple valid order of letters, return any one of them is fine.

 

这道题让给了我们一些按“字母顺序”排列的单词,但是这个字母顺序不是我们熟知的顺序,而是另类的顺序,让我们根据这些“有序”的单词来找出新的字母顺序,这实际上是一道有向图的问题,跟之前的那两道Course Schedule IICourse Schedule的解法很类似,我们先来看BFS的解法,我们需要一个set来保存我们可以推测出来的顺序关系,比如题目中给的例子,我们可以推出的顺序关系有:

t->f
w->e
r->t
e->r

那么set就用来保存这些pair,我们还需要另一个set来保存所有出现过的字母,需要一个一维数组in来保存每个字母的入度,另外还要一个queue来辅助拓扑遍历,我们先遍历单词集,把所有字母先存入ch,然后我们每两个相邻的单词比较,找出顺序pair,然后我们根据这些pair来赋度,我们把ch中入度为0的字母都排入queue中,然后开始遍历,如果字母在set中存在,则将其pair中对应的字母的入度减1,若此时入度减为0了,则将对应的字母排入queue中并且加入结果res中,直到遍历完成,我们看结果res和ch中的元素个数是否相同,若不相同则说明可能有环存在,返回空字符串,参见代码如下:

解法一:

class Solution {
public:
    string alienOrder(vector<string>& words) {
        set<pair<char, char> > s;
        unordered_set<char> ch;
        vector<int> in(256, 0);
        queue<char> q;
        string res = "";
        for (auto a : words) ch.insert(a.begin(), a.end());
        for (int i = 0; i < words.size() - 1; ++i) {
            int mn = min(words[i].size(), words[i + 1].size()), j = 0;
            for (; j < min(words[i].size(), words[i + 1].size()); ++j) {
                if (words[i][j] != words[i + 1][j]) {
                    s.insert(make_pair(words[i][j], words[i + 1][j]));
                    break;
                }
            }
            if (j == mn && words[i].size() > words[i + 1].size()) return "";
        }
        for (auto a : s) ++in[a.second];
        for (auto a : ch) {
            if (in[a] == 0) {
                q.push(a);
                res += a;
            } 
        }
        while (!q.empty()) {
            char c = q.front(); q.pop();
            for (auto a : s) {
                if (a.first == c) {
                    --in[a.second];
                    if (in[a.second] == 0) {
                        q.push(a.second);
                        res += a.second;
                    }
                }
            }
        }
        return res.size() == ch.size() ? res : "";
    }
};

下面来看一种DFS的解法,思路和BFS的很类似,我们需要建立一个二维的bool数组g,然后把出现过的字母的对应的位置都赋为true,然后我们把可以推出的顺序的对应位置也赋为true,然后我们就开始递归调用,如果递归函数有返回false的,说明有冲突,则返回false,递归调用结束后结果res中存了入度不为0的字母,最后把入度为0的字母加到最后面,最后把结果res翻转一下即可,参见代码如下:

解法二:

class Solution {
public:
    string alienOrder(vector<string>& words) {
        vector<vector<bool>> g(26, vector<bool>(26, false));
        vector<bool> path(26, false);
        string res = "";
        for (string word : words) {
            for (char c : word) {
                g[c - 'a'][c - 'a'] = true;
            }
        }
        for (int i = 0; i < words.size() - 1; ++i) {
            int mn = min(words[i].size(), words[i + 1].size()), j = 0;
            for (; j < mn; ++j) {
                if (words[i][j] != words[i + 1][j]) {
                    g[words[i][j] - 'a'][words[i + 1][j] - 'a'] = true;
                    break;
                }
            }
            if (j == mn && words[i].size() > words[i + 1].size()) return "";
        }
        for (int i = 0; i < 26; ++i) {
            if (!dfs(g, i, path, res)) return "";
        }
        for (int i = 0; i < 26; ++i) {
            if (g[i][i]) res += (char)(i + 'a');
        }
        return string(res.rbegin(), res.rend());
    }
    bool dfs(vector<vector<bool>> &g, int idx, vector<bool> &path, string &res) {
        if (!g[idx][idx]) return true;
        path[idx] = true;
        for (int i = 0; i < 26; ++i) {
            if (i == idx || !g[idx][i]) continue;
            if (path[i]) return false;
            if (!dfs(g, i, path, res)) return false;
        }
        path[idx] = false;
        g[idx][idx] = false;
        res += (char)(idx + 'a');
        return true;
    }
};

本文转自博客园Grandyang的博客,原文链接:另类字典[LeetCode] Alien Dictionary ,如需转载请自行联系原博主。

相关文章
|
5月前
|
存储 Swift
在Swift编程语言中,字典(Dictionary)
在Swift编程语言中,字典(Dictionary)
65 3
|
12月前
|
存储 Java Python
多重字典(Multi-Level Dictionary)
多重字典(Multi-Level Dictionary)是一种将多个字典组合在一起的数据结构,用于解决需要在多个维度上查找数据的问题。多重字典可以看作是一个嵌套的字典,每个字典都可以作为其他字典的键。 使用多重字典的场景:
134 3
|
5月前
|
存储 缓存 数据库连接
Python基础教程——字典(Dictionary)
Python基础教程——字典(Dictionary)
|
4月前
|
存储 Python 容器
|
4月前
|
Python 存储 容器
Python 字典(Dictionary)
Python 字典(Dictionary)
|
5月前
|
开发者 Python
【Python 基础】递推式构造字典(dictionary comprehension)
【5月更文挑战第8天】【Python 基础】递推式构造字典(dictionary comprehension)
|
5月前
|
存储 数据处理 Python
Python中的字典(Dictionary)类型:深入解析与应用
Python中的字典(Dictionary)类型:深入解析与应用
44 0
|
5月前
|
存储 算法 数据库
Python字典(Dictionary)
Python字典(Dictionary)
43 0
|
5月前
|
存储 Swift
在Swift编程语言中,字典(Dictionary)
在Swift编程语言中,字典(Dictionary)
410 3
|
5月前
|
Python
在Python中,字典(dictionary)的键(key)具有唯一标识性
在Python中,字典(dictionary)的键(key)具有唯一标识性
132 1