題目描述
給定一個非空01二維數組表示的網格,一個島嶼由四連通(上、下、左、右四個方向)的 1 組成,你可以認爲網格的四周被海水包圍。
請你計算這個網格中共有多少個形狀不同的島嶼。兩個島嶼被認爲是相同的,當且僅當一個島嶼可以通過平移變換(不可以旋轉、翻轉)和另一個島嶼重合。
樣例 1:
11000
11000
00011
00011
給定上圖,返回結果 1。
樣例 2:
11011
10000
00001
11011
給定上圖,返回結果 <font color="#c7254e" face="Menlo, Monaco, Consolas, Courier New, monospace">3</font>。
注意:
11
1
和
1
11
是不同的島嶼,因爲我們不考慮旋轉、翻轉操作。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/number-of-distinct-islands
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
題目分析:
通過嘗試優先遍歷,找出圖中存在的島嶼。還有一個需要解決的問題是如何判斷2個島嶼平移後相同,每個島嶼的所有點放入一個列表,每個點用和島嶼開始位置的曼哈頓座標表示(x0-x_start, y0-y_start),即可以判斷2個島嶼是否平移相同。
代碼實現:
class Solution:
def numDistinctIslands(self, grid: List[List[int]]) -> int:
if not grid or not grid[0]:
return 0
rows, cols = len(grid), len(grid[0])
seen = [[0 for _ in range(cols)] for _ in range(rows)]
dirs = [(0, -1), (0, 1), (-1, 0), (1, 0)]
def dfs_island(grid, row, col, x_from, y_from, island=None):
nonlocal seen
if island is None:
island = []
def is_valid(grid, x, y):
rows, cols = len(grid), len(grid[0])
if x < 0 or x >= rows:
return False
if y < 0 or y >= cols:
return False
return True
seen[row][col] = 1
island.append((row - x_from, col - y_from))
for dir_ in dirs:
dir_x, dir_y = dir_
x, y = row + dir_x, col + dir_y
if is_valid(grid, x, y) and grid[x][y] == 1 and seen[x][y] == 0:
dfs_island(grid, x, y, x_from, y_from, island)
return island
islands = []
def add_island(islands, island):
for ele in islands:
if ele == island:
return
islands.append(island)
for row in range(rows):
for col in range(cols):
if seen[row][col] == 0 and grid[row][col] == 1:
add_island(islands, dfs_island(grid, row, col, row, col))
return len(islands)