[695].島嶼的最大面積

島嶼的最大面積

 


題目

給定一個包含了一些 01 的非空二維數組 grid

一個 島嶼 是由一些相鄰的 1 (代表土地) 構成的組合,這裏的「相鄰」要求兩個 1 必須在水平或者豎直方向上相鄰。你可以假設 grid 的四個邊緣都被 0(代表水)包圍着。

找到給定的二維數組中最大的島嶼面積。(如果沒有島嶼,則返回面積爲 0 。)

示例 1:

[[0,0,1,0,0,0,0,1,0,0,0,0,0],
 [0,0,0,0,0,0,0,1,1,1,0,0,0],
 [0,1,1,0,1,0,0,0,0,0,0,0,0],
 [0,1,0,0,1,1,0,0,1,0,1,0,0],
 [0,1,0,0,1,1,0,0,1,1,1,0,0],
 [0,0,0,0,0,0,0,0,0,0,1,0,0],
 [0,0,0,0,0,0,0,1,1,1,0,0,0],
 [0,0,0,0,0,0,0,1,1,0,0,0,0]]

對於上面這個給定矩陣應返回 6。注意答案不應該是 11 ,因爲島嶼只能包含水平或垂直的四個方向的 1

示例 2:

[[0,0,0,0,0,0,0,0]]

對於上面這個給定的矩陣, 返回 0

 


函數原型

C的函數原型:

int maxAreaOfIsland(int** grid, int gridSize, int* gridColSize){}

 


邊界判斷

int maxAreaOfIsland(int** grid, int gridSize, int* gridColSize){
	if( grid == NULL || gridSize == 0 || gridColSize == NULL || *gridColSize == 0 )
		return 0;
}

 


算法設計:求最大的聯通分量個數

思路:用 DFS or BFS 求聯通分量的個數,最大的那個就是島嶼的最大面積。

  • 四聯通探索與之相連的每一個土地(以及與這些土地相連的土地),那麼探索過的土地總數將是該連通形狀的面積。

  • 爲了確保不會多次訪問同一土地,我們每次經過一塊土地時,將這塊土地的值置爲 0

  • 一般我們會用 visited[] 記錄,但這裏我們可以直接利用 grid[],初始陸地是 1,遍歷如果見到陸地,就 dfs,在 dfs 過程中,每遍歷到一個陸地,就設置爲 0,這樣 grid[]1 的那些點就是要繼續遍歷的點。

int dfs(int** grid, int gridSize, int* gridColSize, int i, int j) {
    if (i < 0 || j < 0 || i == gridSize || j == *gridColSize || grid[i][j] == 0)    // 遞歸結束條件
        return 0;
    
    grid[i][j] = 0;
    int ans = 1;
    int x[4] = {0, -1, 0, 1};
    int y[4] = {-1, 0, 1, 0};
    // 四聯通,如 (x[0], y[0]) -> (0, -1) -> 南,按次序依次是:南、西、北、東。
    for (int k = 0; k < 4; ++k) {    // 四個方向都遍歷一次
        ans += dfs(grid, gridSize, gridColSize, i + x[k], j + y[k]);
    }
    return ans;
}
int maxAreaOfIsland(int** grid, int gridSize, int* gridColSize){
	if( grid == NULL || gridSize == 0 || gridColSize == NULL || *gridColSize == 0 )
		return 0;
    int ans = 0;
    for (int i = 0; i < gridSize; ++i) {
        for (int j = 0; j < *gridColSize; ++j) {
            int t = dfs(grid, gridSize, gridColSize, i, j);
            ans = (ans > t ? ans : t);     // dfs() 返回的是聯通分量的個數,這裏取最大值
        }
    }
    return ans;
}

最大的聯通分量個數的複雜度:

  • 時間複雜度:Θ(n2)\Theta(n^{2})
  • 空間複雜度:Θ(n2)\Theta(n^{2})
     

算法設計:Flood Fill算法

Flood Fill:從某一點開始,按照某種邏輯遍歷不斷查找鄰點。

  • 想象一個二維數組,從左上角(0,0)開始遍歷,直到遍歷到右下角(n-1, n-1)

  • 按照某種邏輯遍歷,可以選 DFSBFS 等,這裏採用 DFS

  • 如果是訪問過的鄰點,就染色,代表已經訪問過來。

  • 一般我們會用 visited[] 記錄,但這裏我們可以直接利用 grid[],初始陸地是 1,遍歷如果見到陸地,就 dfs,在 dfs 過程中,每遍歷到一個陸地,就設置爲 0,這樣 grid[]1 的那些點就是要繼續遍歷的點。

int dfs(int** grid, int gridSize, int* gridColSize, int x, int y) {
    if (x < 0 || y < 0 || x == gridSize || y == *gridColSize || grid[x][y] == 0)    // 遞歸結束條件:出界判斷。
    	return 0;

    grid[x][y] = 0;    // 表示已訪問
    int ans = 1;
    // 一點點可優化的地方,對數組進行索引也會產生性能開銷,可以省了 `x[]`、`y[]` 。
    ans += dfs(grid, gridSize, gridColSize, x - 1, y);  // 西
    ans += dfs(grid, gridSize, gridColSize, x, y + 1);  // 北
    ans += dfs(grid, gridSize, gridColSize, x + 1, y);  // 東
    ans += dfs(grid, gridSize, gridColSize, x, y - 1);  // 南
    return ans;
}
int maxAreaOfIsland(int** grid, int gridSize, int* gridColSize){
	if( grid == NULL || gridSize == 0 || gridColSize == NULL || *gridColSize == 0 )
		return 0;
    int ans = 0;
    for (int i = 0; i < gridSize; ++i) {
        for (int j = 0; j < *gridColSize; ++j) {
            int t = dfs(grid, gridSize, gridColSize, i, j);
            ans = (ans > t ? ans : t);     // dfs() 返回的是聯通分量的個數,這裏取最大值
        }
    }
    return ans;
}

爲了可讀性,可以優化 dfs() 的接口參數。

// 引入一個結構體,減少遞歸接口的參數
struct _graph{
    int** _grid;
    int* _gridColSize;
    int _gridSize;
} g;

int dfs(int x, int y){
    if (x < 0 || y < 0 || x == g._gridSize || y == (*g._gridColSize) || g._grid[x][y] == 0)    return 0;

    g._grid[x][y] = 0;      // 表示已訪問
    int ans = 1;
    ans += dfs(x - 1, y);
    ans += dfs(x, y + 1);
    ans += dfs(x + 1, y);
    ans += dfs(x, y - 1);
    return ans;
}

int maxAreaOfIsland(int** grid, int gridSize, int* gridColSize){
	if( grid == NULL || gridSize == 0 || gridColSize == NULL || *gridColSize == 0 )
		return 0;

    /* 賦值,可減少遞歸參數 */
    g._grid = grid;
    g._gridColSize = gridColSize;
    g._gridSize = gridSize;

    int ans = 0;
    for (int i = 0; i < gridSize; ++i) {
        for (int j = 0; j < *gridColSize; ++j) {
            int t = dfs(i, j);
            ans = (ans > t ? ans : t);     // dfs() 返回的是聯通分量的個數,這裏取最大值
        }
    }
    return ans;
}

Flood Fill算法的複雜度:

  • 時間複雜度:Θ(n2)\Theta(n^{2})
  • 空間複雜度:Θ(n2)\Theta(n^{2})
     

算法設計:並查集

Floodfill 算法的本質是,在一個二維數組中,求解連通分量的問題。實際上,這個問題,也可以非常容易的,使用並查集解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章