題目敘述
- 題目難度:
Medium
- 題目描述: 題目給定一個 m x n 大小的二元陣列
grid
,陣列中 1
代表陸地,0
代表水域,請回傳島嶼的數量。島嶼四面環水,相鄰的陸地會水平或垂直地連接而成。
解法
一開始的想法
這裡的想法就是這應該其實要找的是 這個 Grid 中的所有 connected components 的數量 , 這可以透過對所有尚未訪問節點進行 BFS 或 DFS 並透過一個 counter 來紀錄就可實現。
我的解法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class Solution { public: int row, col; vector<vector<int>> visited; void dfs(int r, int c, vector<vector<char>>& grid){ if(r<0 || r>= grid.size() || c <0 || c>= grid[0].size() || grid[r][c]=='0' || visited[r][c]==1) return; visited[r][c] = 1; dfs(r+1,c, grid); dfs(r-1,c, grid); dfs(r,c+1, grid); dfs(r,c-1, grid); }
int numIslands(vector<vector<char>>& grid){ row = grid.size(); col = grid[0].size(); visited.resize(row, vector<int>(col,0)); int count = 0;
for(int i=0; i<row; i++){ for(int j=0; j<col; j++){ if(grid[i][j]=='1' && visited[i][j] == 0){ dfs(i,j,grid); count++; } } } return count; } };
|
我這裡的主要透過 DFS 來進行走訪,首先對於這題會需要先定義幾個變數來進行記錄:
int row, col
主要用於記錄目前走訪到 grid
的哪一格
vector<vector<int>> visited
用於記錄此格是否拜訪過,0
代表尚未拜訪,1
代表已拜訪
接著回到函數 numIslands
,首先需要初始化 visited
大小,大小要跟 grid
一樣, 這裏透過兩個變數 (row
, col
)來保存行跟列長度,接著要宣告一個變數 count
用於保存島的數量。 接著我們需要透過一個迴圈來迭代每一格,若每一格中的值為 1
並且是尚未造訪過的 visited[i][j] == 0
,這時就需要去遞迴查看跟他相連的節點是否有其他是島嶼,而每次遞迴結束回到 numIslands
就代表找到一個 connected components,這時 count
就可以累加。
這裏的 dfs
跟Tree的 dfs
很像,一樣要去設定終止條件,這裏的終止條件就是:(1)超出範圍 (2)碰到 0
跟 (3)已經造訪過 就會返回。還沒遇到終止條件前,需要先將節點標注為「已造訪」(visited[r][c] =1
) 接著就會去遞迴查找其上下左右鄰接節點是一樣是島嶼。一旦在 numsIslands
都查找完畢後,就會回傳所記錄的 connected components 的數量。
執行結果
BFS 作法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Solution { public: int row, col; vector<vector<int>> visited; int numIslands(vector<vector<char>>& grid){ row = grid.size(); col = grid[0].size(); int offsetRow[4] = {0, 1, 0, -1}; int offsetCol[4] = {1, 0, -1, 0}; visited.resize(row, vector<int>(col,0)); int count = 0; queue<pair<int, int>> q;
for(int i=0; i<row; i++){ for(int j=0; j<col; j++){ if(visited[i][j] == 0 && grid[i][j] == '1'){ visited[i][j] = 1; count++; q.push({i,j}); while(!q.empty()){ pair<int, int>f = q.front(); q.pop(); for(int k=0; k<4 ;k++){ int subRow = f.first + offsetRow[k]; int subCol = f.second + offsetCol[k]; if(subRow>=0 && subRow < row && subCol >=0 && subCol < col && grid[subRow][subCol]=='1' && visited[subRow][subCol] == 0){ visited[subRow][subCol] = 1; q.push({subRow, subCol}); } } } } } } return count; } };
|
BFS 的做法就是透過一個 queue 將尚未訪問且為島嶼的節點推入,並且對於每一層節點,會去找出與他相臨的上下左右的節點是否是島嶼,如果相鄰節點是島嶼且尚未造訪則將其推入到 Queue 中, 並且將 visited
標注為 1。 但核心思想其實一樣,都是要找 connected components 的數量。
執行結果
複雜度
方法 |
時間複雜度 |
空間複雜度 |
分析 |
DFS 方法 |
$O(M \times N)$ |
$O(M \times N)$ |
- 每個節點最多訪問一次,遞迴深度最多為島嶼的大小,需額外的遞迴棧空間(最壞情況 $O(M \times N)$)。 |
BFS 方法 |
$O(M \times N)$ |
$O(M \times N)$ |
- 每個節點最多訪問一次,使用隊列存儲節點,隊列的大小與整個島嶼的節點數成比例。 |