你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。
一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。
请你返回从左上角走到右下角的最小 体力消耗值 。
例:
输入:heights = [[1,2,2],[3,8,2],[5,3,5]]输出:2
解释:路径 [1,3,5,3,5] 连续格子的差值绝对值最大为 2 。
这条路径比路径 [1,2,2,2,5] 更优,因为另一条路径差值最大值为 3 。
题解:最短路径算法
这道题本质上依然是求图中两点间的最短路径,图中边的权值是两顶点的权值之差,路径的长度是路径所包含的边的最大权值。
方法一:迪杰斯特拉算法
迪杰斯特拉算法是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,用一个数组int[ ]dist保存起点到其余各点的最短路径距离,采用贪心算法的策略,每次遍历到起点距离最近且未访问过的顶点的邻接节点并不断更新dist数组,直到扩展到终点为止。
class Solution {
public int minimumEffortPath(int[][] heights) {
int rowLen=heights[0].length;
int colLen=heights.length;
int[][]dir={{0,1},{0,-1},{1,0},{-1,0}};
//路径排序,得到当前的最短路径
PriorityQueue<int[]>queue=new PriorityQueue<int[]>
(Comparator.comparingInt(o -> o[2]));
//是否已经找到图中各顶点的最短路径
boolean[]searched=new boolean[rowLen*colLen];
queue.add(new int[]{0,0,0});
//起点到图中其他各点的最短距离
int[]dist=new int[rowLen*colLen];
//初始化起点到其他各点的最短距离是无穷大
Arrays.fill(dist,Integer.MAX_VALUE);
//起点到起点的最短路径是0
dist[0]=0;
while (!queue.isEmpty()){
int[]peek=queue.poll();
int x=peek[0];
int y=peek[1];
int d=peek[2];
if(searched[x*rowLen+y]){
continue;
}
if(x==colLen-1&&y==rowLen-1){
break;
}
searched[x*rowLen+y]=true;
for(int i=0;i<4;i++){
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(xx>=0&&xx<colLen&&yy>=0&&yy<rowLen&&Math.max(d,Math.abs(heights[x][y]-heights[xx][yy]))<dist[xx*rowLen+yy]){
dist[xx*rowLen+yy]=Math.max(d,Math.abs(heights[x][y]-heights[xx][yy]));
queue.add(new int[]{xx,yy,dist[xx*rowLen+yy]});
}
}
}
return dist[rowLen*colLen-1];
}
}
方法二:并查集
将图中所有边的权值排序,每次从序列中取出当前最小边,将该最小边的两顶点表示成已连接,如此重复,直到起点与终点相连通,检验起点与终点是否连通时可以使用并查集。
class Solution {
public int minimumEffortPath(int[][] heights) {
int rowLen=heights[0].length;
int colLen=heights.length;
unionFind unionFind=new unionFind(colLen*rowLen);
PriorityQueue<int[]>queue=new PriorityQueue<int[]>
(Comparator.comparingInt(o -> o[2]));
for(int i=0;i<colLen;i++){
for(int j=0;j<rowLen;j++){
if(i+1<colLen){
queue.add(new int[]{i*rowLen+j,(i+1)*rowLen+j,Math.abs(heights[i][j]-heights[i+1][j])});
}
if(j+1<rowLen){
queue.add(new int[]{i*rowLen+j,i*rowLen+j+1,Math.abs(heights[i][j]-heights[i][j+1])});
}
}
}
while (!queue.isEmpty()){
int[]peek=queue.poll();
unionFind.union(peek[0],peek[1]);
if(unionFind.connected(0,colLen*rowLen-1)){
return peek[2];
}
}
return 0;
}
}
class unionFind{
int[]parent;
public unionFind(int n){
parent=new int[n];
for(int i=0;i<n;i++){
parent[i]=i;
}
}
public void union(int a,int b){
parent[find(a)]=find(b);
}
public int find(int a){
while(a!=parent[a]){
parent[a]=parent[parent[a]];
a=parent[a];
}
return a;
}
public boolean connected(int a,int b){
return find(a)==find(b);
}
}
版权声明:本文为CY2333333原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。