题目
贪心 + 并查集
union-find 合法树的判定两个条件:一是没环,也就是新加入的边两点不是同一个连通分量的,且最后所有连通分量化为一个count == 1,没落下一个
class Solution {
public int minimumCost(int n, int[][] connections) {
Arrays.sort(connections, (o1,o2) -> {
return Integer.compare(o1[2],o2[2]);
});
int res = 0;
UF uf = new UF(n + 1);
for(int[] connection : connections){
int p = connection[0];
int q = connection[1];
int weight = connection[2];
if(!uf.connected(p,q)){
uf.union(p,q);
res += weight;
}
}
//分量有n + 1个,多了一个0,所以最后应该是一个无环连通树加0,两个分量
return uf.count == 2 ? res : -1;
}
}
class UF{
int count;
int[] parent;
int[] size;
UF(int n){
this.count = n;
parent = new int[n];
size = new int[n];
for(int i = 0; i < n; i++){
parent[i] = i;
size[i] = 1;
}
}
public void union(int p, int q){
int rootP = find(p);
int rootQ = find(q);
if(rootP == rootQ){
return;
}else{
if(size[rootP] > size[rootQ]){
parent[rootQ] = rootP;
size[rootP] += size[rootQ];
count--;
}else{
parent[rootP] = rootQ;
size[rootQ] += size[rootP];
count--;
}
}
}
//路径压缩
public int find(int p){
while(parent[p] != p){
parent[p] = parent[parent[p]];
p = parent[p];
}
return p;
}
public boolean connected(int p, int q){
if(find(p) == find(q)){
return true;
}
return false;
}
}
你能穿过矩阵的最后一天
此题是倒着来,增加陆地,删东西不如增加东西(类似还有美团搬箱子,不如转变成放箱子反向思考),直到端部和底部连通,看见连通应该就考虑并查集,且注意虚拟构造的两点(0和row * col + 1),以及二维转一维
题目
class Solution {
public int latestDayToCross(int row, int col, int[][] cells) {
int[][] directions = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
int cellNum = row * col;
UF uf = new UF(cellNum + 2);
for(int i = 1; i <= col; i++){
uf.union(0, i);
uf.union(cellNum + 1, (row - 1) * col + i);
}
int[][] water = new int[row][col];
for(int i = 0; i < row; i++){
Arrays.fill(water[i], 1);
}
for(int i = cellNum; i > 0; i--){
int[] land = cells[i - 1];
water[land[0] - 1][land[1] - 1] = 0;
int landUFNum = (land[0] - 1) * col + land[1];
for(int[] direction : directions){
int nextRow = land[0] + direction[0];
int nextCol = land[1] + direction[1];
if(nextRow < 1 || nextRow > row || nextCol < 1 || nextCol > col || water[nextRow - 1][nextCol - 1] != 0){
continue;
}
uf.union(landUFNum, (nextRow - 1) * col + nextCol);
}
if(uf.connected(0, cellNum + 1)){
//第一行和最后一行连通了,虽然i是第四天,但是你给了他一块陆地,应该是第三天的情况
return i - 1;
}
}
return -1;
}
}
class UF{
int count;
int[] size;
int[] parent;
UF(int n){
this.count = n;
size = new int[n];
parent = new int[n];
for(int i = 0; i < n; i++){
size[i] = 0;
parent[i] = i;
}
}
public void union(int p, int q){
int rootP = find(p);
int rootQ = find(q);
if(rootP == rootQ){
return;
}
if(size[rootP] > size[rootQ]){
parent[rootQ] = rootP;
size[rootP] += size[rootQ];
count--;
}else{
parent[rootP] = rootQ;
size[rootQ] += size[rootP];
count--;
}
}
public int find(int p){
while(parent[p] != p){
parent[p] = parent[parent[p]];
p = parent[p];
}
return p;
}
public boolean connected(int p, int q){
return find(p) == find(q);
}
}