LeetCode 269. Alien Dictionary

You are given a list of strings words from the dictionary, where words are sorted lexicographically by the rules of this new language.
Derive the order of letters in this language, and return it. If the given input is invalid, return “”. If there are multiple valid solutions, return any of them.

字典序–有向–顺序比较乱但是有规则—拓扑排序
Input: words = [“wrt”,“wrf”,“er”,“ett”,“rftt”]
Output: “wertf”
如果有valid的排序 只需要返回一种就行了 如果没有valid的排序 就返回空字符串

首先 确定用什么去做?BFS
还是 首先 你要把这个图建立起来(Hashmap)in degree表也应该该一并建立起来。因为我们需要直到图的起点从哪里开始的。

如果这两个很难建立的话我们最好重新建一个函数来做这些工作。
BFS函数将新见一个queue用来全力解决我们要解决的拓扑排序问题:真正的一个一个输出表示排序。

虽然下面的的代码非常长 但是思路跟明确:就是建立图和in degree数组。然后利用BFS的queue来一步一步的。
如果仔细观察的话 这道题跟course schedule2几乎是一摸一样的。

class Solution {
    
    public String alienOrder(String[] words) {
        int[] indegree = new int[26];
        Map<Character, Set<Character>> g = new HashMap<>();
        buildGraph(g, indegree, words); //build graph and in degree array
        return bfs(g, indegree);
    }
    
    private String bfs(Map<Character, Set<Character>> g, int[] indegree) {
        StringBuilder sb = new StringBuilder();
        int totalChars = g.size(); //the number of node has outdegree, make a copy for later check
        Queue<Character> q = new LinkedList<>();
        for (char c: g.keySet()) {
            if (indegree[c - 'a'] == 0) { //if a node only have outdegree but its indegree is 0, then it means it can be view as a possibly starting point for this graph(why we say possible? because we initialize hashmap for every char when construct graph)
                sb.append(c);
                q.offer(c); //we offer every starting points to initialize out queue for bfs
            }
        }
        
        while(!q.isEmpty()) {
            char cur = q.poll();
            if (g.get(cur).size() == 0) { //we need to check if the cur is a real starting point, if it is, continue 
                continue;
            }
            //for every point which cur pointer points to, we can view it as our neighbor
            for (char neigh: g.get(cur)) {
                indegree[neigh - 'a']--; //we update to show we have used it
                if (indegree[neigh - 'a'] == 0) { //then it have the same situation as before: a possibly starting point for next level
                    q.offer(neigh); //add to q
                    sb.append(neigh); // append to sb
                }
            }
        }
        return sb.length() == totalChars ? sb.toString() : ""; //supposed to be the same to be valid, if they are not equal, then situations like example 2 must happens
        
    }
    
    private void buildGraph(Map<Character, Set<Character>> g, int[] indegree, String[] words) {
        //initialize all set
        for (String word: words) {
            for (char c: word.toCharArray()) {
                if (!g.containsKey(c)) {
                    g.put(c, new HashSet<>());
                }
                //g.putIfAbsent(c, new HashSet<>());
            }
        }
        
        //interate every adjancent pair of words
        for (int i = 1; i < words.length; i++) {
            String first = words[i-1];
            String second = words[i];
            int len = Math.min(first.length(), second.length());
            
            //for every pair, extract information within it.
            for (int j = 0; j < len; j++) {
                if (first.charAt(j) != second.charAt(j)) {
                    char out = first.charAt(j); 
                    char in = second.charAt(j);
                    
                    if (!g.get(out).contains(in)) {
                        g.get(out).add(in); //update g
                        indegree[in - 'a']++; //update indegree for this char
                    }
                    break; //this is important, because we only need to find the first different char between two strings, remaining information is useless or even harmful if we not break it here
                }
            }
        }
    }
}
posted @ 2020-11-27 10:38  EvanMeetTheWorld  阅读(22)  评论(0)    收藏  举报