Skip to content

1631. Path With Minimum Effort

Coding4 min read

1631. Path With Minimum Effort

這個題目算是比較變態的一題,但是絕對是面試時間內做得出來的題目,要會這題一定要先做過 875. Koko Eating Bananas 並理解特殊型的 Binary Search。

題目的設定條件邏輯並不難,乍看之下,看起來是可以使用深度優先搜索外加,或是透過 Backtrack 來實作一些剪枝。我們要找的是 Minimum Effort ,窮舉出所有的路徑就可以找到最小努力的路徑,實作上的難度也是有點困難,因為我們還需要記錄每個 DFS 到底有沒有超過 Efforts 。

這一題的關鍵是需要**「觀察」**到這一點,那就是我們能不能找出需要努力的範圍區間呢?答案是可以的,因為我們知道其實最小的努力值就是 0 ,這個情況就是從起點到終點,沒有任何的變化(完全是平地),而最大值需要的努力值就是最高地的值。

接著我們要在這個範圍內,找出最小值,這個最小值剛好需要可以從 (0, 0) 走到 (m - 1, n - 1) 。

因此在 DFS 的過程中,如果我們找到的努力值比較高,我們可以直接縮小更多的搜尋範圍,如果努力值太小,就會沒有辦法完成 DFS ,我們就可以快速的結束搜尋。

class Solution:
    def minimumEffortPath(self, heights: List[List[int]]) -> int:
        
        rows = len(heights)
        cols = len(heights[0])
        directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
        
        def dfs(row, col, seen, threshold):
            if row == rows - 1 and col == cols - 1:
                return True
            seen.add((row, col))
            for dr, dc in directions:
                nr, nc = row + dr, col + dc
                if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in seen:
                    if abs(heights[nr][nc] - heights[row][col]) <= threshold:
                        if dfs(nr, nc, seen, threshold):
                            return True
            return False
        

        left = 0
        right = max(max(row) for row in heights)
        while left <= right:
            mid = (left + right) // 2
            if dfs(0, 0, set(), mid):
                right = mid - 1
            else:
                left = mid + 1
        
        return left