本文最后更新于:2020年4月20日 晚上

地址:https://leetcode-cn.com/problems/number-of-islands/

题目

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1:

输入:
11110
11010
11000
00000
输出: 1

示例 2:

输入:
11000
11000
00100
00011
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。

解题思路

很巧的是,之前做过一个同类型的题,岛屿的最大面积

所以这次很容易就有思路了。首先显然的要遍历二维数组找岛屿,很容易,遇到字符 '1' 就是遇到了岛屿,将岛屿数量 count++ ,那么剩下的问题就是,怎么避免重复遇到同一个岛屿?

有过之前做同类型题目的经验,不难想到将当前遇到的岛屿将其置为非 '1' 的状态,因为我们判断一个格子是不是岛屿的一部分,就是看这个格子是不是字符 '1' ,所以只要将其置为非 '1' 即表示当前格子已经是已经计算过的岛屿的一部分或者它本来就不是岛屿。

并不是遇到字符 '1' 只将这个格子置为 '0' ,我们的目的是这个岛屿已经计算过了,再次遇到这个岛屿的任意位置,都不再对其做处理,所以应该使用递归将该岛屿的所有位置都置为 '0'

另外在我的代码中,不是对每一个格子都调用递归函数进行判断,而是在确定当前格子是 '1' 的情况下才调用递归函数,也就是说在递归函数内部,不再需要判断当前递归进来的格子是否为 '0'

代码

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int count = 0;
        for (int i = 0; i < grid.size(); i++) {
            for (int j = 0; j < grid[0].size(); j++) {
                //找到任意一个'1'即表示找到了一个岛屿
                //首先岛屿数量count++,再通过回溯将该岛屿全部置为'0'
                if (grid[i][j] == '1') {
                    count++;
                    backtrack(grid, i, j);
                }
            }
        }
        return count;
    }

    //将grid[i][j]所在的岛屿全部置为0,避免重复判断的问题
    void backtrack(vector<vector<char>>& grid, int i,int j) {
        vector<pair<int, int>> dir = { {-1,0},{1,0},{0,-1},{0,1} };
        grid[i][j] = '0';
        //做选择,上下左右四个方向
        for (auto d : dir) {
            int ii = i + d.first;
            int jj = j + d.second;
            //当且仅当索引ii,jj合法且grid[ii][jj]为'1'是递归
            if (ii >= 0 && ii < grid.size() && jj >= 0 && jj < grid[0].size() && grid[ii][jj] == '1') {
                backtrack(grid, ii, jj);
            }
        }
    }
};