1. 程式人生 > 其它 >【LeetCode】1631.最小體力消耗路徑(Path WIth Minimum Effort)

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

技術標籤:LeetCode演算法題演算法leetcode圖論資料結構

目錄

題目描述

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。