【LeetCode】1631.最小体力消耗路径(Path WIth Minimum Effort)

题目描述

You are a hiker preparing for an upcoming hike. You are given heights, a 2D array of size rows × \times × columns, where heights[row][col] represents the height of cell (row, col). You are situated in the top-left cell, (0, 0), and you hope to travel to the bottom-right cell, (rows-1, columns-1) (i.e., 0-indexed). You can move up, down, left, or right, and you wish to find a route that requires the minimum effort.

A route’s effort is the maximum absolute difference in heights between two consecutive cells of the route.

Return the minimum effort required to travel from the top-left cell to the bottom-right cell.
Example 1:

Input:heights = [[1,2,2],[3,8,2],[5,3,5]]
Output:2
Explanation:
The route of [1,3,5,3,5] has a maximum absolute difference of 2 in consecutive cells.
This is better than the route of [1,2,2,2,5], where the maximum absolute difference is 3.

Example 2:

Input:heights = [[1,2,3],[3,8,4],[5,3,5]]
Output:1
Explanation:The route of [1,2,3,4,5] has a maximum absolute difference of 1 in consecutive cells, which is better than route [1,3,5,3,5].

Example 3:

Input:heights = [[1,2,1,1,1],[1,2,1,2,1],[1,2,1,2,1],[1,2,1,2,1],[1,1,1,2,1]]
Output:0
Explanation:This route does not require any effort.

Constraints:

  • rows == heights.length
  • columns == heights[i].length
  • 1 <= rows, columns <= 100
  • 1 <= heights[i][j] <= 1 0 6 10^6 106

题目来源:https://leetcode-cn.com/problems/path-with-minimum-effort/

题目大意

在本题中,对于某一条路径,其所需花费的体力为所有相邻格子之间的高度差中的最大值,即该条路径的长度。那么,对于输入的rows × \times ×cols二维数组,从起点==(0, 0)==出发,终点是 (rows - 1, cols - 1),题目要求找到一条从起点到终点的花费最小体力的路径,并返回最小体力。

解题方法

这道题的解决办法有很多,目前先介绍下面这几种方法,后续再逐步补充和完善。

方法一:并查集

思路
对于这种与路径相关的题目,核心问题是如何建图,根据题目抽象出一个恰当的图论模型,也就是要回答清楚这几个问题:什么代表图中的节点?什么代表图中的边的权值又该如何计算?
在本题中,对于输入的rows × \times ×cols二维数组,可抽象成如下的一个图论模型:

  • 将输入的二维数组中的每一个格子看成图中的一个节点;并且,为了表示每个节点,需要给每个格子对应的节点赋予一个唯一的节点编号(编号从1开始),对于二维数组中位置为 ( i , j ) (i, j) (i,j)的格子,其对应的节点编号为 i ∗ r o w s + j + 1 i * rows + j + 1 irows+j+1
  • 将相邻(左右相邻或上下相邻)的两个格子对应的节点之间看成存在一条无向边,边的权值为这两个格子高度差的绝对值,即所需花费的体力;并且,无向边可用两个节点的节点编号构成二元组来表示。

基于上述图模型,图的初始状态是所有 r o w s × c o l s rows\times cols rows×cols个节点是孤立的,起点和终点之间不存在一条路径来将它们相连,由于题目要求我们求出所需花费的最小体力,可将所有边按照其权值进行从小到大的排序,然后依次往图中添加无向边(即并查集的”并“操作),并判断起点和终点是否相连(即并查集的”查“操作),若不相连,则继续添加无向边,若相连,当前添加的无向边的权值即为所求。
类似的题目还有778.Swim in Rising Water,与本题的差异在于,需要将相邻格子的最大值看作边的权值。
代码

class Solution {
    // 并查集代码模板
    final int N = 10010;
    int[] p = new int[N];

    public int find(int x){
        if(p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    public void union(int x, int y){
        p[find(x)] = find(y);
    }

    public int minimumEffortPath(int[][] heights) {
        int rows = heights.length;
        int cols = heights[0].length;
        for(int i = 1; i <= rows * cols; i ++) p[i] = i;
        // edges[i][0], edges[i][1]分别为构成边i的两个节点的编号
        // edges[i][2]为边i的权值,即需花费的体力值
        int[][] edges = new int[2 * rows * cols - rows - cols][3];
        int k = 0;
        for(int i = 0; i < rows; i ++){
            for(int j = 0; j < cols; j ++){
                if(j + 1 < cols){
                    edges[k][0] = i * cols + j + 1;
                    edges[k][1] = i * cols + j + 2;
                    edges[k][2] = Math.abs(heights[i][j] - heights[i][j + 1]);
                    k ++;
                }
                if(i + 1 < rows){
                    edges[k][0] = i * cols + j + 1;
                    edges[k][1] = (i + 1) * cols + j + 1;
                    edges[k][2] = Math.abs(heights[i][j] - heights[i + 1][j]);
                    k ++;
                }
            }
        }
        if(edges.length <= 0) return 0;
        Arrays.sort(edges, (o1, o2) -> o1[2] - o2[2]);

        int res = 0;
        for(int i = 0; i < edges.length; i ++){
            union(edges[i][0], edges[i][1]);
            if(find(1) == find(rows * cols)){
                res = edges[i][2];
                break;
            }
        }
        return res;
    }

}

复杂度分析

  • 时间复杂度: O ( m n l o g ( m n ) ) O(mnlog(mn)) O(mnlog(mn)),其中 m m m n n n分别为输入的二维矩阵的行数和列数。在本题中,对于m × \times ×n的二维矩阵,共有m × \times ×n个节点,所构成的边的数量为 O ( m n ) O(mn) O(mn),则对它们进行排序的时间复杂度为 O ( m n l o g ( m n ) ) O(mnlog(mn)) O(mnlog(mn)),其它操作的时间复杂度均比排序小。
  • 空间复杂度: O ( m n ) O(mn) O(mn),需要存储的节点数量为m × \times ×n。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值