LeetCode1631最小体力消耗路径-----并查集、迪杰斯特拉
题目表述
你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。
一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。
请你返回从左上角走到右下角的最小 体力消耗值 。
并查集
题目要求找到从左上角到右下角最小的体力消耗值,一般图的问题很容易想到深度优先搜索和广度优先搜索,此外还可以用并查集判断连通性来决定两节点是否可达,这题可以把每个格子当作一个节点,把相邻格子的高度差绝对值当作边的权重。对边的权重排序,然后重新将题目转化为寻找左上角到右下角的连通,每次取最小权重边进行连接两节点,当左上角到右下角连通时,此时边的权重即为答案。
并查集代码为模板类
class union{
int count;
int[] parents;
public union(int N){
this.count = N;
parents = new int[N];
for(int i = 0; i < N; i++){
parents[i] = i;
}
}
public void unionNode(int x, int y){
int root1 = find(x);
int root2 = find(y);
if(root1 != root2){
parents[root2] = root1;
}
}
public int find(int node){
while(parents[node] != node){
parents[node] = parents[parents[node]];
node = parents[node];
}
return node;
}
public boolean isConnected(int node1, int node2){
return find(node1) == find(node2);
}
}
public int minimumEffortPath(int[][] heights) {
List<int[]> edges = new ArrayList<>();
for (int i = 0; i < heights.length; i++) {
for (int j = 0; j < heights[0].length; j++) {
if(i+1 < heights.length){
edges.add(new int[]{Math.abs(heights[i][j] - heights[i+1][j]), i*heights[0].length + j, (i+1)* heights[0].length + j});
}
if(j+1 < heights[0].length){
edges.add(new int[]{Math.abs(heights[i][j] - heights[i][j+1]), i*heights[0].length + j, i* heights[0].length + j+1});
}
}
}
Collections.sort(edges, (a,b)->a[0] - b[0]);
union un = new union(heights.length * heights[0].length);
for(int[] edge : edges){
int weight = edge[0];
int begin = edge[1];
int end = edge[2];
if(!un.isConnected(begin, end)){
un.unionNode(begin, end);
}
if(un.isConnected(0,heights.length * heights[0].length - 1)){
return weight;
}
}
return 0;
}