一魚多吃: 從 島嶼周長 理解 圖論演算法的本質

閱讀時間約 11 分鐘

今天的官方每日一題是Island Perimeter島嶼周長,很有趣的一題。
題目非常直觀好懂。也很適合拿來作為多角度複習、回顧圖論演算法的好題目。


英文的題目敘述在這裡


題目敘述

題目會給我們一個二維陣列當作地圖,格子點為1代表陸地,格子點為0代表海洋

要求我們以四連通N4的方式拜訪這座島嶼,並且計算這座島嶼的周長

題目保證整張地圖只會有一座島嶼


測試範例

Example 1:

raw-image
Input: grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]
Output: 16
黃色部分的長度代表這座島嶼的周長​
Explanation: The perimeter is the 16 yellow stripes in the image above.

Example 2:

Input: grid = [[1]]
Output: 4

Example 3:

Input: grid = [[1,0]]
Output: 4

約束條件

Constraints:

  • row == grid.length

row的總數 = 地圖的高度

  • col == grid[i].length

col的總數 = 地圖的寬度

  • 1 <= row, col <= 100

高度和寬度都介於 1~100之間。

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

每個格子點一定是零(代表海洋)或一(代表陸地)。

  • There is exactly one island in grid.

保證整張地圖只會有一座島嶼。


什麼時候會遇到島嶼的邊界?

當遇到陸地和海洋交界的時候。

當遇到地圖邊界的時候。

這時候剛好跨過島嶼的邊界,周長累加一


用DFS 探索相連的陸地


先找出的第一塊陸地的格子點,接著用N4 四連通 配合深度優先DFS探索
周圍相鄰的陸地格子點。

當我們遇到陸地和海洋的交界,或者我們遇到地圖邊界時,
這時候剛好跨過島嶼的邊界,周長累加一


時間複雜度O(H * W) 每個格子點最多拜訪一次。

空間複雜度O(H * W) 遞回深度最深是幾乎拜訪整張圖。


DFS 程式碼

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

H, W = len(grid), len(grid[0])

def dfs(r, c):

if not ( 0 <= r < H ) or not( 0 <= c < W) or grid[r][c] == 0:
return 1

if grid[r][c] == '#':
return 0

N4_offset = itertools.pairwise([0, 1, 0, -1, 0])

perimeter = 0
for dr, dc in N4_offset:
nr, nc = r+dr, c+dc

grid[r][c] = '#'
perimeter += dfs(nr, nc)

return perimeter

# ==================================

for r in range(H):
for c in range(W):
if grid[r][c] == 1:
return dfs(r, c)

return -1

用BFS 探索相連的陸地


先找出的第一塊陸地的格子點,接著用N4 四連通 配合廣度優先BFS探索
周圍相鄰的陸地格子點。

當我們遇到陸地和海洋的交界,或者我們遇到地圖邊界時,
這時候剛好跨過島嶼的邊界,周長累加一


時間複雜度O(H * W) 每個格子點最多拜訪一次。

空間複雜度O(H * W) Queue長度最長是幾乎拜訪整張圖。


BFS 程式碼

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

H, W =len(grid), len(grid[0])

perimeter = 0

N4 = list( itertools.pairwise([0, 1, 0, -1, 0]) )

for r in range(H):
for c in range(W):
if grid[r][c] == 1:

bfs_queue = deque([(r,c)])

while bfs_queue:

cur_r, cur_c = bfs_queue.popleft()

#print(f"at {cur_r}, {cur_c}")

if not( 0 <= cur_r < H ) or not( 0 <= cur_c < W ) or grid[cur_r][cur_c] == 0:
# update perimeter count
perimeter += 1
continue

if grid[cur_r][cur_c] == '#':
# Avoid repeated traversal
continue

# Mark current grid as visited
grid[cur_r][cur_c] = '#'

for dr, dc in N4:
nr, nc = cur_r + dr, cur_c + dc
bfs_queue.append( (nr, nc) )

return perimeter

return -1

依序掃描格子點的演算法


除了經典的DFS或者BFS探索演算法之外,我們也可以用掃描格子點的方式。

依序從左到右,從上到下掃描每個格子點。

統計遇到的陸地格子點數目,再統計內部邊緣(就是陸地和陸地相鄰的邊緣)有幾條。

每個陸地格子點會貢獻四條邊緣
內部邊緣會被兩塊相鄰的陸地所共用,所以重複計算了兩次


最後,島嶼的周長

= 陸地格子點貢獻的邊緣數目 - 重複計算的內部邊緣

= 陸地格子點 * 4 - 內部邊緣總數 * 2


時間複雜度O(H * W) 每個格子點最多拜訪一次。

空間複雜度O(1) 只有使用固定尺寸的臨時變數,所需空間為常數級別。


依序掃描格子點的程式碼

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

h, w = len(grid), len(grid[0])

if h * w == 0:
# Quick response for simple case
return 0

land_cell, internal_edge = 0, 0

# scan each cell from top to bottom, from left to right
for y in range(h):
for x in range(w):

if grid[y][x] == 1:
# current cell is land
land_cell += 1

if y and grid[y-1][x]:
# current land cell share one internal edge with neighbor land cell on the top
internal_edge += 1

if x and grid[y][x-1]:
# current land cell share one internal edge with neighbor land cell of the left
internal_edge += 1


# each land cell contributes 4 edge
# each internal edge is repeatedly counted by 2 adjacent land cells
perimeter = land_cell * 4 - internal_edge * 2

return perimeter

關鍵知識點 找出共通模式


根據題意,找出島嶼邊緣的定義。


可以根據範例推敲發現:

當遇到陸地和海洋交界的時候。
當遇到地圖邊界的時候。
這時候剛好跨過島嶼的邊界,周長累加一

結語

條條大路通羅馬,萬變不離其宗。

一個題目可以有好多種解法,但是背後核心觀念都是類似的

只要掌握基本原理,根據題意,找出目標的明確定義,
接著採用合適的圖論演算法去計算所求(島嶼的周長)即可!


希望能幫助讀者、觀眾徹底理解基本圖論演算法BFS / DFS 的原理,

並且能夠舉一反三,洞察其背後的本質和了解相關的應用領域!


感謝收看囉! 我們下篇文章再見~

81會員
417Content count
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
發表第一個留言支持創作者!
題目敘述 題目會給定一顆二元樹的根結點, 要求我們在指定的層樹d,插入新的一層,節點值為v。 原本的左、右子樹,就成為新的那一層的左子樹、右子樹。 題目的原文敘述 測試範例 Example 1: Input: root = [4,2,6,3,1,5], val = 1, depth =
這篇文章,會帶著大家複習以前學過的DFS框架, 並且以圖論的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 DFS 深度優先搜索框架 def dfs( parameter ): # 邊界條件 if base case or stop cond
這篇文章,會帶著大家複習以前學過的BFS框架, 並且以圖論的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 BFS 框架 + 演算法 虛擬碼 # Queue 通常初始化成根結點,作為起點 BFS_queue = deque([root])​ # 先
這篇文章,會帶著大家複習以前學過的DFS框架 結合樹型DP, 並且以路徑和Path Sum的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 DFS 深度優先搜索框架 def dfs( parameter ): if base case or sto
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
這篇文章,會帶著大家複習以前學過的二元搜尋樹(Binary Search Tree)框架, 並且以二分搜尋樹的概念與定義為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 二元搜尋樹(Binary Search Tree)的定義
題目敘述 題目會給定一顆二元樹的根結點, 要求我們在指定的層樹d,插入新的一層,節點值為v。 原本的左、右子樹,就成為新的那一層的左子樹、右子樹。 題目的原文敘述 測試範例 Example 1: Input: root = [4,2,6,3,1,5], val = 1, depth =
這篇文章,會帶著大家複習以前學過的DFS框架, 並且以圖論的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 DFS 深度優先搜索框架 def dfs( parameter ): # 邊界條件 if base case or stop cond
這篇文章,會帶著大家複習以前學過的BFS框架, 並且以圖論的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 BFS 框架 + 演算法 虛擬碼 # Queue 通常初始化成根結點,作為起點 BFS_queue = deque([root])​ # 先
這篇文章,會帶著大家複習以前學過的DFS框架 結合樹型DP, 並且以路徑和Path Sum的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 DFS 深度優先搜索框架 def dfs( parameter ): if base case or sto
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
這篇文章,會帶著大家複習以前學過的二元搜尋樹(Binary Search Tree)框架, 並且以二分搜尋樹的概念與定義為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 二元搜尋樹(Binary Search Tree)的定義
你可能也想看
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
一魚多吃 Linea + 銘文 + Particle Network,今天晚上按頭打 邀請: https://ally.build?inviteCode=AAE6J2 https://ally.build?inviteCode=QOCT15 https://ally.build?inviteC
Thumbnail
這幾年在媒體社群上,著實下了不少功夫,說真的很多人都問說「臉書(Facebook)是不是真的要沒戲唱了?」其實我大多還是抱著比較樂觀的態度,如果你問身邊的年輕人,還用不用FB?那答案恐怕會讓你很心碎,一方面是自己的年紀已經不小,再者可能還會動搖你原本構思好的行銷計畫。 因此很多人在問我FB等等
關於一主多奴,奴寵部份也該注意什麼? 要完全站在奴寵位置思考,還是有點難😅 1.妳能夠在理解之後,打心底接受這樣的關係嗎? 這邊說的接受,不是不停洗腦自己去接受這樣的關係,而是真的能夠接受這樣的關係,理解跟接受是兩回事。 2.妳曾想過想要怎樣的同伴嗎? 因為有時候,可能是妳和她相處的時間
關於一主多奴,無論是主、奴哪方都需要注意的事項。 1.作為主人,你足夠坦誠嗎? 這邊指的坦誠,並不是指等你有了第一個奴一段時間,才突然坦承自己想要多收奴,而是一開始建立關係之前就必須告知讓奴方了解,這是義務,也是作為主人的責任。 在有第一位奴願意理解、接受之後,對後來遇到的第二位甚至往後幾位,
股票可以一魚多吃? 可以,我們熟知的股票,主要是做價差或領股息,但是您知道,還可以做什麼用途嗎? 假如我們不要把股票賣掉,所以不做價差,那麼股票就可以做以下用途。
Thumbnail
說過上餘裕的生活,其實和「財富自由」沒有絕對關係⋯⋯時常覺得夢想和快樂是世上最快被放棄東西,無論是現實勒緊褲袋、或成就地位束縛,是說得頭頭是道卻毫無價值,總是第一個被捨棄⋯⋯
Thumbnail
台北市南港區東明公園相關資訊:: 地址: 台北市南港區南港路二段86巷8弄 (東明社會國宅旁邊) 電話: 02 2585 0192 (管理單位:台北市政府公園路燈工程管理處圓山管理所) 開放時間: 開放空間 (無時間限制) 備註: 公園 東明公園此地佔據在南港區眾多場地精粹之地 ​
Thumbnail
美國農業部將於10/12公佈供需報告,從產量、期末庫存到單產,幾項重要指標皆普遍被預期會較前次調高。 產量:從4374百萬英斗上調至4415百萬英斗(區間4374- 4466百萬英斗) 期末庫存:從1850百萬英斗上調至3000百萬英斗(區間1610- 3730百萬英斗)
Thumbnail
童文薰律師在童溫層節目中整理出蔡英文一魚多吃的記錄 我其實蠻意外,在童文薰律師揭露蔡英文論文原稿一魚多吃之後,御用媒體會真的當回事發報導洗白的;因為這真的不是一般人會關心的事。但《芋傳媒》還真的引用了一個臉書粉專:《翻譯有要緊》的貼文煞有介事的這麼做了。
Thumbnail
蔡英文的國圖版論文公佈之後,除了抄襲爭議外的另一個質疑,就是童文薰律師揭露的一魚多吃。而其中有趣的一則花絮就是...
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
一魚多吃 Linea + 銘文 + Particle Network,今天晚上按頭打 邀請: https://ally.build?inviteCode=AAE6J2 https://ally.build?inviteCode=QOCT15 https://ally.build?inviteC
Thumbnail
這幾年在媒體社群上,著實下了不少功夫,說真的很多人都問說「臉書(Facebook)是不是真的要沒戲唱了?」其實我大多還是抱著比較樂觀的態度,如果你問身邊的年輕人,還用不用FB?那答案恐怕會讓你很心碎,一方面是自己的年紀已經不小,再者可能還會動搖你原本構思好的行銷計畫。 因此很多人在問我FB等等
關於一主多奴,奴寵部份也該注意什麼? 要完全站在奴寵位置思考,還是有點難😅 1.妳能夠在理解之後,打心底接受這樣的關係嗎? 這邊說的接受,不是不停洗腦自己去接受這樣的關係,而是真的能夠接受這樣的關係,理解跟接受是兩回事。 2.妳曾想過想要怎樣的同伴嗎? 因為有時候,可能是妳和她相處的時間
關於一主多奴,無論是主、奴哪方都需要注意的事項。 1.作為主人,你足夠坦誠嗎? 這邊指的坦誠,並不是指等你有了第一個奴一段時間,才突然坦承自己想要多收奴,而是一開始建立關係之前就必須告知讓奴方了解,這是義務,也是作為主人的責任。 在有第一位奴願意理解、接受之後,對後來遇到的第二位甚至往後幾位,
股票可以一魚多吃? 可以,我們熟知的股票,主要是做價差或領股息,但是您知道,還可以做什麼用途嗎? 假如我們不要把股票賣掉,所以不做價差,那麼股票就可以做以下用途。
Thumbnail
說過上餘裕的生活,其實和「財富自由」沒有絕對關係⋯⋯時常覺得夢想和快樂是世上最快被放棄東西,無論是現實勒緊褲袋、或成就地位束縛,是說得頭頭是道卻毫無價值,總是第一個被捨棄⋯⋯
Thumbnail
台北市南港區東明公園相關資訊:: 地址: 台北市南港區南港路二段86巷8弄 (東明社會國宅旁邊) 電話: 02 2585 0192 (管理單位:台北市政府公園路燈工程管理處圓山管理所) 開放時間: 開放空間 (無時間限制) 備註: 公園 東明公園此地佔據在南港區眾多場地精粹之地 ​
Thumbnail
美國農業部將於10/12公佈供需報告,從產量、期末庫存到單產,幾項重要指標皆普遍被預期會較前次調高。 產量:從4374百萬英斗上調至4415百萬英斗(區間4374- 4466百萬英斗) 期末庫存:從1850百萬英斗上調至3000百萬英斗(區間1610- 3730百萬英斗)
Thumbnail
童文薰律師在童溫層節目中整理出蔡英文一魚多吃的記錄 我其實蠻意外,在童文薰律師揭露蔡英文論文原稿一魚多吃之後,御用媒體會真的當回事發報導洗白的;因為這真的不是一般人會關心的事。但《芋傳媒》還真的引用了一個臉書粉專:《翻譯有要緊》的貼文煞有介事的這麼做了。
Thumbnail
蔡英文的國圖版論文公佈之後,除了抄襲爭議外的另一個質疑,就是童文薰律師揭露的一魚多吃。而其中有趣的一則花絮就是...