1. 程式人生 > >Leetcode 200. 島嶼的個數(擴充套件)

Leetcode 200. 島嶼的個數(擴充套件)

1.題目描述

給定一個由 '1'(陸地)和 '0'(水)組成的的二維網格,計算島嶼的數量。一個島被水包圍,並且它是通過水平方向或垂直方向上相鄰的陸地連線而成的。你可以假設網格的四個邊均被水包圍。

示例 1:

輸入:
11110
11010
11000
00000

輸出: 1

示例 2:

輸入:
11000
11000
00100
00011

輸出: 3

 

2.解題思路

演算法核心框架:深度搜索+遞迴

  • 深度搜索:整個島嶼是一個“二維矩陣”(vector<vectro<char>>),使用深度優先搜尋遍歷一遍整個矩陣;
  • 遞迴:當掃描到'1'時,呼叫infect()函式,將該 ‘1’ 上下左右相鄰的位置都感染為 ‘2’,遞迴呼叫infect()的結果是從起始的 ‘1’ 開始而相連的一片‘1’都被感染為 ‘2’;

 

3.提交程式碼

class Solution {
public:
     int numIslands(vector<vector<char>>& grid) {
        //行空 或 列空
        if(grid.empty() || grid[0].empty()){
            return 0;
        }
        
int N = grid.size();//grid網格的列長 int M = grid[0].size();//grid網格的行長 int res = 0; //深度優先搜尋 for(int i = 0; i < N; ++i){ for(int j = 0; j < M; ++j){ if(grid[i][j] == '1'){ ++res;//只計數作為起始感染點的1的個數,即為島嶼個數 infect(grid,i,j,N,M); } } }
return res; } void infect(vector<vector<char>>& grid,int i,int j,int N,int M){ if(i<0 || i>=N || j<0 || j>= M || grid[i][j] != '1'){ return; } grid[i][j] = '2'; infect(grid,i+1,j,N,M); infect(grid,i-1,j,N,M); infect(grid,i,j-1,N,M); infect(grid,i,j+1,N,M); } };

 

4.擴充套件解法——並查集

假設題目給的資料非常多,也就是所要查詢的矩陣相當大,這種情況下,我們該怎麼辦?很明顯,上面的解法只能在單機上執行,效率有上限。

因此,我們需要採用多工處理的“平行計算”的思路,將大的原始矩陣分割成多個小的矩陣,分佈在多臺機器上進行計算,最後合併每臺機器的島嶼數量,並去重,得到最終的島嶼總數。

#問題的難點:邊界資訊該如何合併?

01111 | 11110
11000 | 00000
11000 | 00000
01111 | 11110
島數1    島數2
合併結果:島數1 (怎麼得到?)

#解決思路:需要儲存的關鍵資訊有兩個:

  • (1)每個分矩陣的島嶼個數;
  • (2)記錄邊界點的感染中心——需要使用到並查集的結構,快速查詢兩個‘1’是否屬於同一個集合(相同的感染中心)。

#並查集知識點