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];
}
}