1631 Path With Minimum Effort

You are a hiker preparing for an upcoming hike. You are given heights, a 2D array of size rows x 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] <= 10^6

一开始看题,各种纠结到底能不能不暴力搜,用DP。想了半天好像没有什么递推式。就算做也只能memo。但memo好像也不太行。所以只好看答案了。谁知,是一条二分答案。但其中用到BFS或者DFS。判断条件是,能不能用cost为mid,走完这图。因为最大的数值是10^6,所以6次能搜完range。(log(range))。然后,图的遍历,是O(V + E)。V是m*n,E也是m*n,所以T:O(m*n)。S:O(m*n),visited的size

public int minimumEffortPath(int[][] heights) {
    if (heights == null || heights.length == 0 || heights[0].length == 0) {
        return Integer.MAX_VALUE;
    }

    int start = 0;
    int end = 1000000;

    while (start + 1 < end) {
        int mid = start + (end - start) / 2;
        if (canReach(mid, heights)) {
            end = mid;
        } else {
            start = mid;
        }
    }

    if (canReach(start, heights)) {
        return start;
    } else {
        return end;
    }
}

private boolean canReach(int cost, int[][] heights) {        
    int n = heights.length;
    int m = heights[0].length;

    boolean[][] visited = new boolean[n][m];

    int[] x = {0, 0, 1, -1};
    int[] y = {1, -1, 0, 0};

    Queue<Integer> queue = new LinkedList<>();

    queue.offer(0);
    visited[0][0] = true;

    while (!queue.isEmpty()) {
        int cur = queue.poll();
        int curi = cur / m;
        int curj = cur % m;

        for (int k = 0; k < 4; k++) {
            int nexti = curi + x[k];
            int nextj = curj + y[k];

            if (inBound(nexti, nextj, n, m) && !visited[nexti][nextj]) {
                if (Math.abs(heights[nexti][nextj] - heights[curi][curj]) <= cost) {
                    visited[nexti][nextj] = true;
                    queue.offer(nexti * m + nextj);
                    // 提前return,没有也不错,但有了快点
                    if (nexti == n - 1 && nextj == m - 1) {
                        return true;
                    }
                }
            }
        }

    }
    // 如果这里直接说false的话,那么只有一个点的图就不对了。所以要判断是否visit到了最后一个点
    return visited[n - 1][m - 1];
}

private boolean inBound(int row, int col, int n, int m) {
    if (row < 0 || col < 0 || row >= n || col >= m) {
        return false;
    }
    return true;
}

Last updated

Was this helpful?