LeetCode Top Interview Questions 269. Alien Dictionary (Java版; Hard)

冷不防 2023-07-03 10:59 92阅读 0赞

welcome to my blog

LeetCode Top Interview Questions 269. Alien Dictionary (Java版; Hard)

题目描述

  1. 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 non-empty words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language.
  2. Example 1:
  3. Input:
  4. [
  5. "wrt",
  6. "wrf",
  7. "er",
  8. "ett",
  9. "rftt"
  10. ]
  11. Output: "wertf"
  12. Example 2:
  13. Input:
  14. [
  15. "z",
  16. "x"
  17. ]
  18. Output: "zx"
  19. Example 3:
  20. Input:
  21. [
  22. "z",
  23. "x",
  24. "z"
  25. ]
  26. Output: ""
  27. Explanation: The order is invalid, so return "".
  28. Note:
  29. You may assume all letters are in lowercase.
  30. You may assume that if a is a prefix of b, then a must appear before b in the given dictionary.
  31. If the order is invalid, return an empty string.
  32. There may be multiple valid order of letters, return any one of them is fine.

第一次做;巩固一下拓扑排序, 这里也可以说是拓扑遍历; 相似的题:两道Course Schedule II 210题和Course Schedule 207题

  1. /* 拓扑排序, 是BFS? 拓扑排序中的关键组件: 1. 有向图; 优先级高的指向优先级低的 2. 入度表; 可以使用哈希表或者数组记录 3. 记录入度为0的节点的队列; 可以使用LinkedList 4. 记录拓扑排序的结果; 可以使用集合记录; 如果拓扑排序的结果和节点数量一样则说明图中没有环, 否则说明有环 核心1: BFS, 拓扑排序 核心2: 建立映射关系, 优先级高的指向优先级低的 核心3: 建立映射关系时, 找出相邻两个字符串中第一个不同的字符 核心4: 记录不同字符的数量, 也就是不能计入重复的 核心5: 如果sb中的元素个数等于count, 说明图中没有环; 否则说明有环 细节: 注意map的用法 细节: 这里需要强制转换为char. queue.add((char)('a'+i)); */
  2. class Solution {
  3. public String alienOrder(String[] words) {
  4. //记录对应关系, 如果a优先于b, 则key是a, value是b
  5. HashMap<Character, Set<Character>>map = new HashMap<>();
  6. int n = words.length;
  7. //相邻两个单词比较; 注意: 前一个单词优先级高于后一个单词
  8. for(int i=0; i<n-1; i++){
  9. //细节:找出相邻两个字符串中第一个不同的字符
  10. for(int j=0; j<words[i].length() && j<words[i+1].length(); j++){
  11. //对应位置字符相同的话, 则比较下一个
  12. char ch1 = words[i].charAt(j), ch2 = words[i+1].charAt(j);
  13. if(ch1 == ch2)
  14. continue;
  15. //细节...
  16. // map.getOrDefault(ch1, new HashSet<Character>()).add(ch2); //这么写是错的
  17. Set<Character> set = map.getOrDefault(ch1, new HashSet<Character>());
  18. set.add(ch2);
  19. map.put(ch1, set); //一定要通过map.put()
  20. //作用是什么? 通过这个案例: 输入:["za","zb","ca","cb"] 输出"abzc"; 不加这句输出是""
  21. break;
  22. }
  23. }
  24. //记录每个字符的入度
  25. int[] inDegree = new int[26];
  26. //-1表示字符没出现过
  27. Arrays.fill(inDegree, -1);
  28. //让出现过的字符入度为0
  29. for(String word : words){
  30. for(char ch : word.toCharArray()){
  31. inDegree[ch-'a'] = 0;
  32. }
  33. }
  34. //核心: 记录不同字符的数量; 注意跳过重复的
  35. int count = 0;
  36. for(int i=0; i<26; i++){
  37. if(inDegree[i]==0)
  38. count++;
  39. }
  40. //根据map更新字符的入度
  41. for(Character ch : map.keySet()){
  42. for(Character c : map.get(ch)){
  43. inDegree[c-'a']++;
  44. }
  45. }
  46. //使用队列记录入度为0的字符
  47. LinkedList<Character> queue = new LinkedList<>();
  48. for(int i=0; i<26; i++)
  49. if(inDegree[i]==0)
  50. //细节, 这里需要强制转换为char
  51. queue.add((char)('a'+i));
  52. //记录拓扑排序结果
  53. StringBuilder sb = new StringBuilder();
  54. while(!queue.isEmpty()){
  55. Character ch = queue.poll();
  56. //将拓扑排序结果加入sb
  57. sb.append(ch);
  58. //更新ch指向的邻居们的入度
  59. if(map.containsKey(ch)){
  60. for(Character c : map.get(ch)){
  61. inDegree[c-'a']--;
  62. if(inDegree[c-'a']==0)
  63. queue.add(c);
  64. }
  65. }
  66. }
  67. //如果sb中的元素个数等于count, 说明图中没有环; 否则说明有环
  68. return sb.length()==count? sb.toString() : "";
  69. }
  70. }

力扣优秀题解

  1. class Solution {
  2. public String alienOrder(String[] words) {
  3. //1.构建图
  4. Map<Character, Set<Character>> map = new HashMap<>();
  5. for (int i = 0; i < words.length - 1; i++) {
  6. for (int j = 0; j < words[i].length() && j < words[i + 1].length(); j++) {
  7. //如果字符相同,比较下一个
  8. if (words[i].charAt(j) == words[i + 1].charAt(j)) continue;
  9. //保存第一个不同的字符顺序
  10. Set<Character> set = map.getOrDefault(words[i].charAt(j), new HashSet<>());
  11. set.add(words[i + 1].charAt(j));
  12. map.put(words[i].charAt(j), set);
  13. break;
  14. }
  15. }
  16. //2.拓扑排序
  17. //创建保存入度的数组
  18. int[] degrees = new int[26];
  19. Arrays.fill(degrees, -1);
  20. //注意,不是26字母都在words中出现,所以出度分为两种情况:没有出现的字母出度为-1,出现了的字母的出度为非负数
  21. for (String str : words) {
  22. //将出现过的字符的出度设定为0
  23. for (char c : str.toCharArray())
  24. degrees[c - 'a'] = 0;
  25. }
  26. for (char key : map.keySet()) {
  27. for (char val : map.get(key)) {
  28. degrees[val - 'a']++;
  29. }
  30. }
  31. //创建StringBuilder保存拓扑排序
  32. StringBuilder sb = new StringBuilder();
  33. //创建一个Queue保存入度为0的节点
  34. Queue<Character> list = new LinkedList<>();
  35. int count = 0;//计算图中节点数
  36. for (int i = 0; i < 26; i++) {
  37. if (degrees[i] != -1) count++;
  38. if (degrees[i] == 0) {
  39. list.add((char) ('a' + i));
  40. }
  41. }
  42. while (!list.isEmpty()) {
  43. Character cur = list.poll();
  44. sb.append(cur);
  45. //将邻接点出度-1
  46. if (map.containsKey(cur)) {
  47. Set<Character> set = map.get(cur);
  48. for (Character c : set) {
  49. degrees[c - 'a']--;
  50. if (degrees[c - 'a'] == 0) list.add(c);
  51. }
  52. }
  53. }
  54. //判断是否有环
  55. if (sb.length() != count) return "";
  56. else return sb.toString();
  57. }
  58. }

发表评论

表情:
评论列表 (有 0 条评论,92人围观)

还没有评论,来说两句吧...

相关阅读