1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| class Solution { public String alienOrder(String[] words) { Map<Character, Set<Character>> nodeNeighbor = new HashMap<>(); Map<Character, Integer> inDegreeCount = new HashMap<>(); Set<Character> letterSet = new HashSet<>(); addLetter(words[0], letterSet); for (int i = 1; i < words.length; i++) { addLetter(words[i], letterSet); int diffPos = findDiffPos(words[i - 1], words[i]); if (diffPos != -1) { char smallerLetter = words[i - 1].charAt(diffPos), biggerLetter = words[i].charAt(diffPos); if (!nodeNeighbor.containsKey(smallerLetter) || !nodeNeighbor.get(smallerLetter).contains(biggerLetter)) { nodeNeighbor.computeIfAbsent(smallerLetter, (key) -> new HashSet<>()).add(biggerLetter); inDegreeCount.put(biggerLetter, inDegreeCount.getOrDefault(biggerLetter, 0) + 1); } } else if (words[i].length() < words[i - 1].length()) { return ""; } } StringBuilder alienOrder = new StringBuilder(); Deque<Character> nodes = new ArrayDeque<>(); for (char letter : letterSet) { if (!inDegreeCount.containsKey(letter)) { nodes.offer(letter); } } while (!nodes.isEmpty()) { char currLetter = nodes.poll(); alienOrder.append(currLetter); if (nodeNeighbor.containsKey(currLetter)) { for (char neighbor : nodeNeighbor.get(currLetter)) { inDegreeCount.put(neighbor, inDegreeCount.get(neighbor) - 1); if (inDegreeCount.get(neighbor) == 0) { nodes.offer(neighbor); } } } } return alienOrder.length() == letterSet.size() ? alienOrder.toString() : ""; }
private int findDiffPos(String str1, String str2) { if (str1.equals(str2)) return -1; if (str1.length() > str2.length()) return findDiffPos(str2, str1); int ptr1 = 0, ptr2 = 0; while (ptr1 < str1.length() && str1.charAt(ptr1) == str2.charAt(ptr2)) { ptr1 += 1; ptr2 += 1; } return ptr1 == str1.length() ? -1 : ptr1; }
private void addLetter(String word, Set<Character> letterSet) { for (char letter : word.toCharArray()) { letterSet.add(letter); } } }
|
拓扑排序的经典题.
这里就是相邻两个word比较, 找出第一个不一样letter的位置, 此时靠前的word的这个位置的letter就靠前, 靠后的word的这个位置的letter就靠后. 出现两个word一模一样或者一个word是另一个word的substring的时候, 返回-1.
需要注意三个点. 第一个是每个字母都是一个node, 小的字母指向大的字母. 第二是edge不要重复算, 如果之前遇到过node1 -> node2, 那么再遇到的时候就不要重复计算. 第三是如果出现一个string是另一个substring的情况, 要保证靠后的string是较长的string.
时间复杂度: O(ns)
空间复杂度: O(ns)