平安歸途 最安全的一條路 (圖論應用) Leetcode #2812

閱讀時間約 11 分鐘

題目敘述

題目給定一個二元矩陣,用1來代表小偷所在的位置,0代表沒有小偷。

每個格子點的安全分數為該點距離小偷的曼哈頓距離(Manhanttan distance)

一條路徑的安全分數是路徑上所有安全分數的最小值

移動的時候可以往上、下、左、右走一格。

請問從左上角走到右下角的最安全路徑的安全分數是多少


原本的英文題目敘述


測試範例

Example 1:

raw-image


Input: grid = [[1,0,0],[0,0,0],[0,0,1]]
Output: 0
Explanation: All paths from (0, 0) to (n - 1, n - 1) go through the thieves in cells (0, 0) and (n - 1, n - 1).


Example 2:

raw-image


Input: grid = [[0,0,1],[0,0,0],[0,0,0]]
Output: 2
Explanation: The path depicted in the picture above has a safeness factor of 2 since:
- The closest cell of the path to the thief at cell (0, 2) is cell (0, 0). The distance between them is | 0 - 0 | + | 0 - 2 | = 2.
It can be shown that there are no other paths with a higher safeness factor.


Example 3:

raw-image
Input: grid = [[0,0,0,1],[0,0,0,0],[0,0,0,0],[1,0,0,0]]
Output: 2
Explanation: The path depicted in the picture above has a safeness factor of 2 since:
- The closest cell of the path to the thief at cell (0, 3) is cell (1, 2). The distance between them is | 0 - 1 | + | 3 - 2 | = 2.
- The closest cell of the path to the thief at cell (3, 0) is cell (3, 2). The distance between them is | 3 - 3 | + | 0 - 2 | = 2.
It can be shown that there are no other paths with a higher safeness factor.
 

約束條件

Constraints:

  • 1 <= grid.length == n <= 400

輸入陣列的邊長n介於1~400之間。

  • grid[i].length == n

輸入陣列的邊長以n代表

  • grid[i][j] is either 0 or 1.

每個陣列元素一定是零(沒有小偷) 或 一(有小偷)。

  • There is at least one thief in the grid.

地圖中至少有一位小偷。


演算法 Dijkstra找最安全路徑


怎麼計算每個格子點的安全分數?

根據定義,
根據每個格子點和小偷的曼哈頓距離來計算。
( delta x + delta y = 水平距離差值 + 垂直距離差值)


怎麼找最安全路徑?

起點設為左上角,終點設為右下角。

使用Dijkstra algorithm,
每回合都從當前四聯通N4的鄰居取出安全分數最高的格子點,作為探索前進的方向


程式碼 Dijkstra找最安全路徑

class Solution:
def maximumSafenessFactor(self, grid: List[List[int]]) -> int:

# Heigh as well as width of board
h, w = len(grid), len(grid[0])

## Simple case:
# Either source or destination has thief.
# Not safe always => Safety score = 0
if grid[0][0] == 1 or grid[h-1][w-1] == 1:
return 0

## Dictionary
# key: coordination
# value: corresponding safeness score
safeness = defaultdict(lambda :-1)

bfs_queue = deque([])

## Step 1:
# Collect thief information
for r in range(h):
for c in range(w):
if grid[r][c] == 1:
safeness[r,c] = 0
bfs_queue.append((0, r, c))

## Step 2:
# Propagate safeness value based on Manhanttan distance to thief
N4_vector = [(-1,0),(1,0),(0,-1),(0,1)]
while bfs_queue:
dis, r, c = bfs_queue.popleft()

for dr, dc in N4_vector:
nr, nc = r + dr, c + dc

if 0 <= nr < h and 0 <= nc < w and safeness[nr,nc] == -1:
safeness[nr,nc] = dis + 1
bfs_queue.append((dis + 1, nr, nc))


## Step 3:
# Try to find safest path from source to destination, flip to negative to fit in python's minHeap in order to select safest path
safety_queue = [(-safeness[0,0], 0, 0)]

# Initialize to source point
seen = set([(0,0)])

# Dijkstra: always pick safer path first
while safety_queue:
safety, r, c = heappop(safety_queue)

# Flip back to positive value
safety *= -1

# Base case: we've reached destination
if (r, c) == (h-1, w-1):
return safety

## General cases:
# Check neighbor in N4, and update safety value, push back into priority queue on safety
for dr, dc in N4_vector:
nr, nc = r + dr, c + dc

# Neighbor is on the board, and it has not been seen yet.
if 0 <= nr < h and 0 <= nc < w and (nr, nc) not in seen:

# Update path safety = min{ safety value on the path so far}
path_safety = min(safety, safeness[nr,nc] )

# Push back into priorty queue
heappush(safety_queue, (-path_safety, nr, nc))

# Mark this neighbor as seen
seen.add((nr, nc))


# If no path to destination, return -1 as no solution
return -1

複雜度分析

時間複雜度: O(n^2 log n^2 )

需要一個2D掃描,掃描每個格子點恰好掃描一次,耗費O(n^2)時間。

接著使用Dijkstra algorithm + heap挑選最安全路徑,至多有O(n^2)個格子點,調整heap時,至多花費O(log n^2)的時間。


總共時間成本為O(n^2 + n^2 log n^2 ) = O( n^2 log n^2)


空間複雜度: O(n^2)

探索深度最深為O(n^2),最多就是將近探索整張圖,也就是queue的最大成本。


關鍵知識點

曼哈頓距離
= Manhantann distance
= 兩點之間的水平距離差距 + 垂直距離差距 = delta x + delta y


當遇到最短路徑最安全路徑最高分數路徑...等場景時,
聯想到圖論中的Dijkstra algorithm + priority queue

具體的優先權策略就根據題意進行計算即可
在本題中,最安全的路徑就是安全分數最高的路徑。


Reference

[1] Find the Safest Path in a Grid - LeetCode

avatar-img
90會員
425內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
這篇文章討論了從二維整數陣列中挖掘金礦的問題。文章使用DFS模擬N4走法來解決問題,並提供了時間複雜度和空間複雜度的分析。這將有助於瞭解如何從地圖中挖取最多金礦。文章中提到了相關的關鍵知識點和參考資料。
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
題目敘述 輸入給定一個鏈結串列的head node。 要求我們進行化簡,只要某個節點的右手邊存在比較大的節點,就刪除掉。 例如 5->2->13->3 5的右手邊有13,所以5刪除掉。 2的右手邊有13,所以2刪除掉。 13的右手邊沒有更大的節點,所以13留著。 3的右手邊沒有更大
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 組合數之和 Combination Sum 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所以可能的情況,
今天的一魚三吃系列是透過 兩點之間是否存在一條路徑的題目,來回顧以前學過的DFS、BFS和Disjoint Set,鞏固圖論演算法的知識點。 英文的題目敘述在這裡 題目敘述 給定我們已知n個節點的圖,和圖上的每一條無向邊edges。 請問給定的起點start和終點end是否存在一條路徑可
今天的官方每日一題是Island Perimeter島嶼周長,很有趣的一題。 題目非常直觀好懂。也很適合拿來作為多角度複習、回顧圖論演算法的好題目。 英文的題目敘述在這裡 題目敘述 題目會給我們一個二維陣列當作地圖,格子點為1代表陸地,格子點為0代表海洋。 要求我們以四連通N4的方式拜訪
這篇文章討論了從二維整數陣列中挖掘金礦的問題。文章使用DFS模擬N4走法來解決問題,並提供了時間複雜度和空間複雜度的分析。這將有助於瞭解如何從地圖中挖取最多金礦。文章中提到了相關的關鍵知識點和參考資料。
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
題目敘述 輸入給定一個鏈結串列的head node。 要求我們進行化簡,只要某個節點的右手邊存在比較大的節點,就刪除掉。 例如 5->2->13->3 5的右手邊有13,所以5刪除掉。 2的右手邊有13,所以2刪除掉。 13的右手邊沒有更大的節點,所以13留著。 3的右手邊沒有更大
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 組合數之和 Combination Sum 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所以可能的情況,
今天的一魚三吃系列是透過 兩點之間是否存在一條路徑的題目,來回顧以前學過的DFS、BFS和Disjoint Set,鞏固圖論演算法的知識點。 英文的題目敘述在這裡 題目敘述 給定我們已知n個節點的圖,和圖上的每一條無向邊edges。 請問給定的起點start和終點end是否存在一條路徑可
今天的官方每日一題是Island Perimeter島嶼周長,很有趣的一題。 題目非常直觀好懂。也很適合拿來作為多角度複習、回顧圖論演算法的好題目。 英文的題目敘述在這裡 題目敘述 題目會給我們一個二維陣列當作地圖,格子點為1代表陸地,格子點為0代表海洋。 要求我們以四連通N4的方式拜訪
你可能也想看
Google News 追蹤
如果你清楚自己要去哪裡,那麼到達目的地就簡單多了。在生活中,我們經常會遇到各種各樣的選擇和決定。有時候,一大堆事情擺在面前,讓人不知所措,但其實只要我們確定了自己的方向,每一步都會變得明朗許多。 就像是出門前先查好地圖,知道哪條路最快,哪條路最省油,你自然能輕鬆抵達目的地,不會浪費時間兜圈子。
Thumbnail
這是假裝某個空間中的兩端點距離很遠的方式
Thumbnail
本篇文章介紹了路徑的概念和兩種不同的路徑運用。這些知識對於網頁開發非常重要,能夠幫助網站開發者更好地管理資源文件的位置。文章通過實際例子和相對路徑的範例來解釋這些概念。希望通過這篇文章,讀者能夠清楚地瞭解路徑的概念,並在日後的開發中能夠靈活運用。
Thumbnail
上篇進一步認識基本的圖形架構與三大 Graph 算法,那首先從 shortest path 開始,我們會陸續去理解這些算法,以及可能的應用,如果還沒有看過上一篇的,可以點以下連結~那我們就開始吧! 【圖論Graph】Part1:初探圖形與圖形演算法之應用
Thumbnail
解決電腦上遇到的問題、證明正確性、探討效率 並且很著重溝通,說服別人你做的事是正確且有效率的。 內容: 計算模型、資料結構介紹、演算法介紹、時間複雜度介紹。
如果你清楚自己要去哪裡,那麼到達目的地就簡單多了。在生活中,我們經常會遇到各種各樣的選擇和決定。有時候,一大堆事情擺在面前,讓人不知所措,但其實只要我們確定了自己的方向,每一步都會變得明朗許多。 就像是出門前先查好地圖,知道哪條路最快,哪條路最省油,你自然能輕鬆抵達目的地,不會浪費時間兜圈子。
Thumbnail
這是假裝某個空間中的兩端點距離很遠的方式
Thumbnail
本篇文章介紹了路徑的概念和兩種不同的路徑運用。這些知識對於網頁開發非常重要,能夠幫助網站開發者更好地管理資源文件的位置。文章通過實際例子和相對路徑的範例來解釋這些概念。希望通過這篇文章,讀者能夠清楚地瞭解路徑的概念,並在日後的開發中能夠靈活運用。
Thumbnail
上篇進一步認識基本的圖形架構與三大 Graph 算法,那首先從 shortest path 開始,我們會陸續去理解這些算法,以及可能的應用,如果還沒有看過上一篇的,可以點以下連結~那我們就開始吧! 【圖論Graph】Part1:初探圖形與圖形演算法之應用
Thumbnail
解決電腦上遇到的問題、證明正確性、探討效率 並且很著重溝通,說服別人你做的事是正確且有效率的。 內容: 計算模型、資料結構介紹、演算法介紹、時間複雜度介紹。