最小生成树算法(Prim, Kruskal)&& 拓扑排序
连接所有点的最小费用
class Solution { public int minCostConnectPoints(int[][] points) { //prim算法,时间复杂度 n^2 int res = 0, n = points.length; int[][] g = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { g[i][j] = Math.abs(points[i][0] - points[j][0]) + Math.abs(points[i][1] - points[j][1]); } } //点的集合,已经放入集合为true boolean[] v = new boolean[n]; //lowest[i] 表示 点i 到已放入集合的点的最短距离 int[] lowest = new int[n]; //先放入 点0 v[0] = true; //未放入点 i 到已放入点的集合的最短距离,这里是[0],[1, n-1] for (int i = 1; i < n; i++) { lowest[i] = g[0][i]; } //还有n - 1个点没有放入集合 for (int i = 1; i < n; i++) { int min = Integer.MAX_VALUE, index = -1; for (int j = 0; j < n; j++) { if (v[j]) continue; if (min > lowest[j]) { index = j; min = lowest[j]; } } res += min; v[index] = true; //更新lowest for (int j = 0; j < n; j++) { if (v[j]) continue; lowest[j] = Math.min(lowest[j], g[index][j]); } } return res; } }
class Solution { public int minCostConnectPoints(int[][] points) { //Kruskal算法 int n = points.length, res = 0; //优先队列(小到大) PriorityQueue<Edge> heap = new PriorityQueue<>((o1, o2) -> o1.dis - o2.dis); //并查集找环 UF uf = new UF(n); //按边的大小从小到达放入优先队列 for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int dis = Math.abs(points[i][0] - points[j][0]) + Math.abs(points[i][1] - points[j][1]); heap.offer(new Edge(i, j, dis)); } } int mark = 0; while (!heap.isEmpty()) { Edge e = heap.poll(); if (uf.union(e.x, e.y)){ res += e.dis; mark++; } if (mark == n - 1) break; } return res; } class Edge { private int x, y, dis; public Edge(int x, int y, int dis) { this.x = x; this.y = y; this.dis = dis; } } //用并查集 class UF{ int[] parent; public UF(int n) { parent = new int[n]; for (int i = 0; i < n; i++) { parent[i] = i; } } private int find(int x) { if (x != parent[x]) { parent[x] = find(parent[x]); } return parent[x]; } public boolean union(int a, int b) { int rootA = find(a); int rootB = find(b); //如果a, b在连通,那么加入a, b就会有环 if (rootA == rootB) return false; parent[rootA] = rootB; return true; } } }
拓扑排序
class Solution { public int[] findOrder(int numCourses, int[][] prerequisites) { int[] res = new int[numCourses]; int index = 0; //构造图 List<List<Integer>> list = new ArrayList<>(); for (int i = 0; i < numCourses; i++) { list.add(new ArrayList<>()); } //入度 int[] indgree = new int[numCourses]; for (int[] arr : prerequisites) { indgree[arr[0]]++; list.get(arr[1]).add(arr[0]); } Queue<Integer> queue = new LinkedList<>(); //先把入度为0,即没有约束的点放入 for (int i = 0; i < numCourses; i++) { if (indgree[i] == 0) { queue.add(i); } } while (!queue.isEmpty()) { int x = queue.poll(); res[index++] = x; //想象删除这个点,那么这个点指向的点的入度会减一 for (int a : list.get(x)) { if (--indgree[a] == 0) { queue.offer(a); } } } return index == numCourses ? res : new int[0]; } }