课程表2问题的两种解法
解法一:拓扑排序,根据节点的入度信息
public class Solution { public int[] findOrder(int numCourses, int[][] prerequisites) { // 先处理极端情况 if (numCourses <= 0) { return new int[0]; } // 邻接表表示 HashSet<Integer>[] graph = new HashSet[numCourses]; for (int i = 0; i < numCourses; i++) { graph[i] = new HashSet<>(); } // 入度表 int[] inDegree = new int[numCourses]; // 遍历 prerequisites 的时候,把 邻接表 和 入度表 都填上 for (int[] p : prerequisites) { graph[p[1]].add(p[0]); inDegree[p[0]]++; } //这里因为List中没有poll方法,所以要用LinkedList声明! LinkedList<Integer> queue = new LinkedList<>(); for (int i = 0; i < numCourses; i++) { if (inDegree[i] == 0) { queue.addLast(i); } } ArrayList<Integer> res = new ArrayList<>(); while (!queue.isEmpty()) { // 当前入度为 0 的结点 Integer inDegreeNode = queue.removeFirst(); // 加入结果集中 res.add(inDegreeNode); // 下面从图中删去 // 得到所有的后继课程,接下来把它们的入度全部减去 1 HashSet<Integer> nextCourses = graph[inDegreeNode]; for (Integer nextCourse : nextCourses) { inDegree[nextCourse]--; // 马上检测该结点的入度是否为 0,如果为 0,马上加入队列 if (inDegree[nextCourse] == 0) { queue.addLast(nextCourse); } } } // 如果结果集中的数量不等于结点的数量,就不能完成课程任务,这一点是拓扑排序的结论 int resLen = res.size(); if (resLen == numCourses) { int[] ret = new int[numCourses]; for (int i = 0; i < numCourses; i++) { ret[i] = res.get(i); } return ret; } else { return new int[0]; } } }
解法二:利用深搜,代码有模板可寻
class Solution { public int[] findOrder(int numCourses, int[][] prerequisites) { if(numCourses <=0) return new int[0]; if(prerequisites.length ==0){ int[] res = new int[numCourses]; for(int i = 0; i < res.length; i++){ res[i] = i; } return res; } HashSet<Integer>[] graph = new HashSet[numCourses]; //一旦创建了这样一个数字,就一定要对每个数组元素初始化。 for(int i = 0; i < numCourses; i++){ graph[i] = new HashSet<>(); } for(int[] p: prerequisites){ graph[p[1]].add(p[0]); } //对每一个元素,创建这样一个 int[] marked = new int[numCourses]; Stack<Integer> stack = new Stack<>(); for(int i = 0; i < numCourses; i++){ if(dfs(i,graph,marked,stack)) return new int[0]; } int[] res = new int[numCourses]; for(int i = 0; i < numCourses; i++){ res[i] = stack.pop(); } return res; } //可以用marked数组,也可以用visited布尔数组记录 //marked[i] == 2相当于visited[i] == true; //marked[i] == 1相当于onstack[i] == true;后者是出现在火星词典的那道题中的解法。 public boolean dfs(int i, HashSet<Integer>[] graph, int[] marked, Stack<Integer> stack){ if(marked[i] == 1) return true; // 等于1表示当前正在访问的节点有一次被访问,因此相当于有环; if(marked[i] == 2) return false; // 等于2表示当前节点已经被标记为访问过,且不构成环; marked[i] =1; HashSet<Integer> nextCourses = graph[i]; for(Integer nextCourse:nextCourses){ if(dfs(nextCourse, graph,marked,stack)) return true; } marked[i] =2; stack.push(i); return false; } }
火星字典题目解法如下:深搜,其中的dfs是用来判断构造的图中是否有环
class Solution { public HashMap<Character,Set<Character>> buildGraph(String[] list){ HashMap<Character, Set<Character>> graph = new HashMap<>(); for(int i = 0; i < list.length-1; i++){ String a = list[i]; String b = list[i+1]; for(int j = 0; j < a.length() && j < b.length(); j++){ //只构建不一样的部分 if(a.charAt(j) == b.charAt(j)) continue; Set<Character> set = graph.getOrDefault(a.charAt(j), new HashSet<Character>()); set.add(b.charAt(j)); graph.put(a.charAt(j),set); break; } } return graph; } public String alienOrder(String[] words) { HashMap<Character, Set<Character>> graph = buildGraph(words); StringBuilder res = new StringBuilder(); boolean[] visited = new boolean[26]; for(char c = 'a'; c <='z';c++){ if(!visited[c-'a']) if(graph.containsKey(c) && dfs(c,graph,visited,new boolean[26],res)) return ""; } for(String s:words){ for(char i: s.toCharArray()){ if(!visited[i-'a']){ res.append(i); visited[i-'a'] = true; } } } return res.toString(); } public boolean dfs(char c, HashMap<Character, Set<Character>> graph, boolean[] visited, boolean[] onstack,StringBuilder sb){ //获取下标 int index = c - 'a'; if(onstack[index]) return true; if(visited[index]) return false; visited[index] = true; onstack[index] = true; //这个char c 一定是在这个图里面的,以为上面的函数alien中要先判断这个字符在图中containsKey() //重中之重:但是为什么还要再用getOrDefault函数呢,因为上一个函数的HashMap中的value部分Set<Character>部分并没有默认初始化! Set<Character> set = graph.getOrDefault(c,new HashSet<Character>()); for(Character cc: set){ if(dfs(cc,graph,visited,onstack,sb)) return true; } onstack[index] = false; sb.insert(0,c); return false; } }