zoukankan      html  css  js  c++  java
  • 269. Alien Dictionary

        /*
         * 269. Alien Dictionary
         * 2016-6-24 by Mingyang
         * 这是一道很难的题目,但是思路很清晰,一看就知道是graph里面的题目,不过在具体细节上面,我们还需要考虑
         * 首先是这里的顺序,我一开始是每两个char之间都比较一下,存在一个map里面,然后每一个string第一个字符再纵向比较
         * 然后后面用queue,再remove,一是太复杂,二是remove的时候没有度的概念,如果remove掉很多点
         * 下面的代码是我见到比较清晰的
         * https://segmentfault.com/a/1190000003795463
         */
          public String alienOrder(String[] words) {
                // 节点构成的图
                Map<Character, Set<Character>> graph = new HashMap<Character, Set<Character>>();
                // 节点的计数器
                Map<Character, Integer> indegree = new HashMap<Character, Integer>();
                // 结果存在这个里面
                StringBuilder order = new StringBuilder();
                // 初始化图和计数器
                initialize(words, graph, indegree);
                // 建图并计数
                buildGraphAndGetIndegree(words, graph, indegree);
                // 拓扑排序的最后一步,根据计数器值广度优先搜索
                topologicalSort(order, graph, indegree);
                // 如果大小相等说明无环
                return order.length() == indegree.size() ? order.toString() : "";
            }    
            private void initialize(String[] words, Map<Character, Set<Character>> graph, Map<Character, Integer> indegree){
                for(String word : words){
                    for(int i = 0; i < word.length(); i++){
                        char curr = word.charAt(i);
                        // 对每个单词的每个字母初始化计数器和图节点
                        if(graph.get(curr) == null){
                            graph.put(curr, new HashSet<Character>());
                        }
                        if(indegree.get(curr) == null){
                            indegree.put(curr, 0);
                        }
                    }
                }
            }    
            private void buildGraphAndGetIndegree(String[] words, Map<Character, Set<Character>> graph, Map<Character, Integer> indegree){
                Set<String> edges = new HashSet<String>();
                for(int i = 0; i < words.length - 1; i++){
                // 每两个相邻的词进行比较
                    String word1 = words[i];
                    String word2 = words[i + 1];
                    for(int j = 0; j < word1.length() && j < word2.length(); j++){
                        char from = word1.charAt(j);
                        char to = word2.charAt(j);
                        // 如果相同则继续,找到两个单词第一个不相同的字母
                        if(from == to) continue;
                        // 如果这两个字母构成的边还没有使用过,则
                        if(!edges.contains(from+""+to)){
                            Set<Character> set = graph.get(from);
                            set.add(to);
                            // 将后面的字母加入前面字母的Set中
                            graph.put(from, set);
                            Integer toin = indegree.get(to);
                            toin++;
                            // 更新后面字母的计数器,+1
                            indegree.put(to, toin);
                            // 记录这条边已经处理过了
                            edges.add(from+""+to);
                            break;
                        }
                    }
                }
            }    
            private void topologicalSort(StringBuilder order, Map<Character, Set<Character>> graph, Map<Character, Integer> indegree){
                // 广度优先搜索的队列
                Queue<Character> queue = new LinkedList<Character>();
                // 将有向图的根,即计数器为0的节点加入队列中
                for(Character key : indegree.keySet()){
                    if(indegree.get(key) == 0){
                        queue.offer(key);
                    }
                }
                // 搜索
                while(!queue.isEmpty()){
                    Character curr = queue.poll();
                    // 将队头节点加入结果中
                    order.append(curr);
                    Set<Character> set = graph.get(curr);
                    if(set != null){
                        // 对所有该节点指向的节点,更新其计数器,-1
                        for(Character c : set){
                            Integer val = indegree.get(c);
                            val--;
                            // 如果计数器归零,则加入队列中待处理
                            if(val == 0){
                                queue.offer(c);
                            }
                            indegree.put(c, val);
                        }
                    }
                }
            }
  • 相关阅读:
    撩课-Python-每天5道面试题-第8天
    声明提前、原型、静态方法的一些所得
    梳理ajax
    两数之和、整数反转、回文数
    node 基础API(fs)
    node 基础API(event)
    node 基础API(Buffer)
    node 基础API(path)
    node 调试技巧
    node process(进程) 几个常用属性
  • 原文地址:https://www.cnblogs.com/zmyvszk/p/5617343.html
Copyright © 2011-2022 走看看