拓扑排序介绍:
1、课程表 - 力扣(LeetCode)
思路:
- 通过Map<Integer, List<Integer>> 来创建邻接图,数组来表示入度
- 然后遍历课程数组,建图
- 然后再拓扑排序,bfs
- 最后在遍历入度数组,判断有没有环,即是不是入度都为零
- 代码:
class Solution { public boolean canFinish(int n, int[][] p) { //1、准备工作 //统计每个顶点的如度 int[] in = new int[n]; //构造邻接图表 Map<Integer, List<Integer>> edges = new HashMap<>(); //2、建图 for(int i = 0; i < p.length; i++){ int a = p[i][0]; int b = p[i][1]; if(!edges.containsKey(b)){ edges.put(b, new ArrayList<>()); } edges.get(b).add(a); //入度加一 in[a]++; } //3、拓扑排序 //先把入度为零的点加入到对列中 Queue<Integer> q = new LinkedList<>(); for(int i = 0; i < n; i++){ if(in[i] == 0){ q.offer(i); } } //bfs while(!q.isEmpty()){ int t = q.poll(); for(int a : edges.getOrDefault(t, new ArrayList<>())){ in[a]--; if(in[a] == 0){ q.offer(a); } } } //4、判断是否有环 for(int x : in){ if(x != 0){ return false; } } return true; } }
2、课程表 II - 力扣(LeetCode)
思路:
- 和上一题一样,把最后出队的元素加入到数组中即可
- 代码:
public int[] findOrder(int n, int[][] p) { //准备工作 List<List<Integer>> edges = new ArrayList<>(); int[] in = new int[n]; for(int i = 0; i < n; i++){ edges.add(new ArrayList<>()); } //建图 for(int i = 0; i < p.length; i++){ int a = p[i][0]; int b = p[i][1]; edges.get(b).add(a); in[a]++; } //拓扑排序 //入度为0 的点入队 Queue<Integer> q = new LinkedList<>(); for(int i = 0; i < n; i++){ if(in[i] == 0){ q.add(i); } } //bfs int[] ret = new int[n]; int index = 0; while(!q.isEmpty()){ int t = q.poll(); ret[index++] = t; for(int a : edges.get(t)){ in[a]--; if(in[a] == 0){ q.add(a); } } } //判断 if(index == n){ return ret; }else{ return new int[0]; } }
3、 火星词典 - 力扣(LeetCode)
思路:
- 拓扑排序
建图:用Map<Character, Set<Character>>
统计入度:Map<Character, Integer>- 细节问题:当第一组的字符串长度大于第二组的字符串时,不合法
- 代码:
class Solution { Map<Character, Set<Character>> edges = new HashMap<>();//邻接表 Map<Character, Integer> in = new HashMap<>();//统计每个节点的入度 boolean check; public String alienOrder(String[] words) { //1、初始化入度的哈希表和建邻接表 for(String s : words){ for(int i = 0; i < s.length(); i++){ char ch = s.charAt(i); in.put(ch, 0); } } int n = words.length; for(int i = 0; i < n; i++){ for(int j = i + 1; j < n; j++){ add(words[i],words[j]); if(check == true){ return ""; } } } //2、拓扑排序 Queue<Character> q = new LinkedList<>(); //将入度为零的节点都入队 for(char ch : in.keySet()){ if(in.get(ch) == 0){ q.offer(ch); } } StringBuffer ret = new StringBuffer(); //遍历队列 while(!q.isEmpty()){ char t = q.poll(); ret.append(t); if(!edges.containsKey(t)){ continue; } for(char ch : edges.get(t)){ in.put(ch, in.get(ch) - 1); if(in.get(ch) == 0){ q.add(ch); } } } //3、判断,是否入度都是为零 for(char ch : in.keySet()){ if(in.get(ch) != 0){ return ""; } } return ret.toString(); } //处理字符串 public void add(String s1, String s2){ int n = Math.min(s1.length(), s2.length()); int i = 0; for( ; i < n; i++){ char c1 = s1.charAt(i); char c2 = s2.charAt(i); if(c1 != c2){ if(!edges.containsKey(c1)){ edges.put(c1, new HashSet<>()); } if(!edges.get(c1).contains(c2)){ edges.get(c1).add(c2); in.put(c2, in.get(c2)+1); } break; } } if(i == s2.length() && i < s1.length()){ check = true; } } }