LeetCode 269 Alien Dictionary

713 阅读2分钟

LeetCode 269 Alien Dictionary

链接:leetcode.com/problems/al…

方法:拓扑排序BFS

时间复杂度:O(mn),n代表words数组的长度,m代表words里面最长的单词的长度

空间复杂度:O(1),主要是题目说了只包括英文小写字母,那么不管是图的表示,还是Queue,都应该是在常数范围内

想法:根据给的东西构建字母的先后顺序,这个描述想到拓扑排序还是不难的。拓扑排序也是算法当中非常基础的内容,实现起来无非就是BFS外加一个记录入度的哈希表。这个题主要难点在于如何正确地构建这张图。构图的思路是用一个index扫描原数组,然后每次都跟它的后一个字符串进行比较,因为前一个字符串的字典序比后一个字符串更靠前,因此这俩直接比较出来那一个第一个不同的字符,就可以得到一对字符之间的字典序关系。比如说"wrt","wrf",我们有个指针找到第三位,那么显然t在f之前,t的child里面就可以放进去f。这个题还有个比较蛋疼的点,在于题目给的数据不一定是合法的,有可能根本构造不出来。所以要加入一行代码:

if (index == words[i + 1].length() && index < words[i].length()) { return null; }

你扫描完了这俩字符串,结果发现后面字符串是前面字符串的一个前缀,然后前面字符串比后面那个还长,比如说"abc""a"前面,这肯定是不合理。这种情况我们用return null解决,假如返回的图是null,我们会认为构图的时候出问题了,然后直接返回空字符串表明,根据这输入数据做不了。

代码:

class Solution {
    public String alienOrder(String[] words) {
        Map<Character, Set<Character>> graph = createGraph(words);
        return topologySort(graph);
    }
    
    private String topologySort(Map<Character, Set<Character>> graph) {
        if (graph == null) {
            return "";
        }
        
        Map<Character, Integer> in = new HashMap<>();
        for (Character key : graph.keySet()) {
            if (!in.containsKey(key)) {
                in.put(key, 0);
            }
            Set<Character> child = graph.get(key);
            for (Character c : child) {
                int tmp = in.getOrDefault(c, 0) + 1;
                in.put(c, tmp);
            }
        }
        
        Queue<Character> queue = new LinkedList<>();
        int cnt = 0;
        StringBuilder sb = new StringBuilder();
        for (Character key : in.keySet()) {
            if (in.get(key) == 0) {
                queue.offer(key);
            }
        }
        
        while (!queue.isEmpty()) {
            Character head = queue.poll();
            cnt++;
            sb.append(head);
            for (Character neighbor : graph.get(head)) {
                int tmp = in.get(neighbor) - 1;
                in.put(neighbor, tmp);
                if (tmp == 0) {
                    queue.offer(neighbor);
                }
            }
        }
        
        return cnt == graph.size() ? sb.toString() : "";
    }
    
    private Map<Character, Set<Character>> createGraph(String[] words) {
        Map<Character, Set<Character>> map = new HashMap<>();
        
        for (int i = 0; i < words.length; i++) {
            for (int j = 0; j < words[i].length(); j++) {
                char c = words[i].charAt(j);
                if (!map.containsKey(c)) {
                    map.put(c, new HashSet<Character>());
                }
            }
        }
        
        for (int i = 0; i < words.length - 1; i++) {
            int index = 0;
            while (index < words[i].length() && index < words[i + 1].length()) {
                char cf = words[i].charAt(index);
                char cl = words[i + 1].charAt(index);
                if (cf != cl) {
                    map.get(cf).add(cl);
                    break;
                }
                index++;
            }
            if (index == words[i + 1].length() && index < words[i].length()) {
                return null;
            }
        }
        
        return map;
    }
}