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

小松鼠-avatar-img
發佈於演算法題目解析 個房間
更新 發佈閱讀 11 分鐘

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


英文的題目敘述在這裡


題目敘述

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

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

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


測試範例

Example 1:

vocus|新世代的創作平台
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 的原理,

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


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

留言
avatar-img
小松鼠的演算法樂園
99會員
428內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
2024/09/26
Leetcode 729. My Calendar I 給定一個行事曆的class定義和行程安排的介面interface。 請完成下列function 1.建構子MyCalendar() 初始化MyCalendar物件 2.boolean book(int start, int end) 插入新行程
Thumbnail
2024/09/26
Leetcode 729. My Calendar I 給定一個行事曆的class定義和行程安排的介面interface。 請完成下列function 1.建構子MyCalendar() 初始化MyCalendar物件 2.boolean book(int start, int end) 插入新行程
Thumbnail
2024/09/10
Insert Greatest Common Divisors in Linked List 題目給定一個鏈結串列, 請在兩兩節點之間加入一個新節點,新節點的值為兩者之間的最大公因數。 最後返回新串列的head node作為答案。
Thumbnail
2024/09/10
Insert Greatest Common Divisors in Linked List 題目給定一個鏈結串列, 請在兩兩節點之間加入一個新節點,新節點的值為兩者之間的最大公因數。 最後返回新串列的head node作為答案。
Thumbnail
2024/09/09
2326. Spiral Matrix IV 題目給定一個Linked list和對應的矩陣高度m、寬度n。 請依照順時針的拜訪順序, 從左上角出發,依照次序把Linked List的內容填到矩陣裡。 如果有剩餘不足的空位,就填補-1。 最後將填補好的矩陣返回作為答案。
Thumbnail
2024/09/09
2326. Spiral Matrix IV 題目給定一個Linked list和對應的矩陣高度m、寬度n。 請依照順時針的拜訪順序, 從左上角出發,依照次序把Linked List的內容填到矩陣裡。 如果有剩餘不足的空位,就填補-1。 最後將填補好的矩陣返回作為答案。
Thumbnail
看更多
你可能也想看
Thumbnail
題目敘述 題目會給定我們一個字串s,和一組字庫wordDict。 問我們能不能透過字串串接的方式,從字庫裡面的字拼成原本的字串s? 可以的話,返回True。 無解的話,返回False。 註: 題目還允許重複使用字庫裡面的字去串接。
Thumbnail
題目敘述 題目會給定我們一個字串s,和一組字庫wordDict。 問我們能不能透過字串串接的方式,從字庫裡面的字拼成原本的字串s? 可以的話,返回True。 無解的話,返回False。 註: 題目還允許重複使用字庫裡面的字去串接。
Thumbnail
子集合生成是一道經典的組合類上機考和面試題目。本篇文章介紹多個不同的解決方案,以及相關演算法框架。主要目標是給定n個相異的元素,產生所有的子集合。
Thumbnail
子集合生成是一道經典的組合類上機考和面試題目。本篇文章介紹多個不同的解決方案,以及相關演算法框架。主要目標是給定n個相異的元素,產生所有的子集合。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
今天的官方每日一題是Island Perimeter島嶼周長,很有趣的一題。 題目非常直觀好懂。也很適合拿來作為多角度複習、回顧圖論演算法的好題目。 英文的題目敘述在這裡 題目敘述 題目會給我們一個二維陣列當作地圖,格子點為1代表陸地,格子點為0代表海洋。 要求我們以四連通N4的方式拜訪
Thumbnail
今天的官方每日一題是Island Perimeter島嶼周長,很有趣的一題。 題目非常直觀好懂。也很適合拿來作為多角度複習、回顧圖論演算法的好題目。 英文的題目敘述在這裡 題目敘述 題目會給我們一個二維陣列當作地圖,格子點為1代表陸地,格子點為0代表海洋。 要求我們以四連通N4的方式拜訪
Thumbnail
題目敘述 題目給定我們一顆二元樹的根節點,要求我們計算出從根節點到葉子節點的偽回文路徑路徑有幾條? 偽回文路徑路徑 的定義: 路徑經過重新排列之後,可以形成回文Palindrome,也就是頭尾鏡像對稱。 ​ 例如: 1 -> 3 -> 3 重新排列之後,可以形成 3 -> 1 -> 3
Thumbnail
題目敘述 題目給定我們一顆二元樹的根節點,要求我們計算出從根節點到葉子節點的偽回文路徑路徑有幾條? 偽回文路徑路徑 的定義: 路徑經過重新排列之後,可以形成回文Palindrome,也就是頭尾鏡像對稱。 ​ 例如: 1 -> 3 -> 3 重新排列之後,可以形成 3 -> 1 -> 3
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
題目敘述 給定兩個字串word1和word2,每次操作時,可以有三個選項 插入一個字元 刪除一個字元 替換一個字元 請問把word1轉換成word2的最小操作次數是多少? 題目的原文敘述 約束條件 Constraints: 0 <= word1.length, word2.le
Thumbnail
題目敘述 給定兩個字串word1和word2,每次操作時,可以有三個選項 插入一個字元 刪除一個字元 替換一個字元 請問把word1轉換成word2的最小操作次數是多少? 題目的原文敘述 約束條件 Constraints: 0 <= word1.length, word2.le
Thumbnail
題目敘述 題目會給定我們輸入邊長陣列nums,請問我們從裡面能夠建構出來的多邊形的最大周長是多少? 如果無解,返回-1 題目的原文敘述 約束條件 Constraints: 3 <= n <= 10^5 輸入陣列長度nums介於3 ~ 十萬 之間。 1 <= nums[i] <=
Thumbnail
題目敘述 題目會給定我們輸入邊長陣列nums,請問我們從裡面能夠建構出來的多邊形的最大周長是多少? 如果無解,返回-1 題目的原文敘述 約束條件 Constraints: 3 <= n <= 10^5 輸入陣列長度nums介於3 ~ 十萬 之間。 1 <= nums[i] <=
Thumbnail
今天的一魚三吃系列是透過 兩點之間是否存在一條路徑的題目,來回顧以前學過的DFS、BFS和Disjoint Set,鞏固圖論演算法的知識點。 英文的題目敘述在這裡 題目敘述 給定我們已知n個節點的圖,和圖上的每一條無向邊edges。 請問給定的起點start和終點end是否存在一條路徑可
Thumbnail
今天的一魚三吃系列是透過 兩點之間是否存在一條路徑的題目,來回顧以前學過的DFS、BFS和Disjoint Set,鞏固圖論演算法的知識點。 英文的題目敘述在這裡 題目敘述 給定我們已知n個節點的圖,和圖上的每一條無向邊edges。 請問給定的起點start和終點end是否存在一條路徑可
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
題目敘述 題目會給定我們一個n值,要求我們列出從0 ~ n 之間,每個整數有幾個bit1,以陣列的形式返回答案。 例如n=3時 因為 0 = 0b 0 1 = 0b 1 2 = 0b 10 3 = 0b 11 輸出答案為[0, 1, 1, 2] 題目的原文敘述 測試範例 E
Thumbnail
題目敘述 題目會給定我們一個n值,要求我們列出從0 ~ n 之間,每個整數有幾個bit1,以陣列的形式返回答案。 例如n=3時 因為 0 = 0b 0 1 = 0b 1 2 = 0b 10 3 = 0b 11 輸出答案為[0, 1, 1, 2] 題目的原文敘述 測試範例 E
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News