200. Number of Islands

Given a 2d grid map of '1’s (land) and '0’s (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1:

Input:
11110
11010
11000
00000

Output: 1
Example 2:

Input:
11000
11000
00100
00011

Output: 3

这就是很典型的深度优先广度优先了,可以看作简易版的求连通分量个数。
代码:
深度优先搜索;

class Solution {
public:
    int numIslands(vector>& grid) {
        int res = 0;
        int nrow = grid.size();
        if (nrow < 1) return res;
        int ncol = grid[0].size();
        
        vector> isVisited(nrow, vector(ncol, 0));
        for (int i = 0; i < nrow; i++) {
            for (int j = 0; j < ncol; j++) {
                if (grid[i][j] == '1' && isVisited[i][j] == 0) {
                    dfs(i, j, grid, isVisited);
                    res++;
                }
            }
        }
        
        return res;
    }
    void dfs(int i, int j, vector>& grid, vector>& isVisited) {
        if (isVisited[i][j] == 1) return;
        isVisited[i][j] = 1;
        int nrow = grid.size();
        int ncol = grid[0].size();
        if (i - 1 >= 0 && grid[i - 1][j] == '1') dfs(i - 1, j, grid, isVisited);
        if (i + 1 < nrow && grid[i + 1][j] == '1') dfs(i + 1, j, grid, isVisited);
        if (j - 1 >= 0 && grid[i][j - 1] == '1') dfs(i, j - 1, grid, isVisited);
        if (j + 1 < ncol && grid[i][j + 1] == '1') dfs(i, j + 1, grid, isVisited);
    }
};

贴一个别人的深度优先代码对比一下:

class Solution {
public:
    int numIslands(vector > &grid) {
        if (grid.empty() || grid[0].empty()) return 0;
        int m = grid.size(), n = grid[0].size(), res = 0;
        vector > visited(m, vector(n, false));
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == '1' && !visited[i][j]) {
                    numIslandsDFS(grid, visited, i, j);
                    ++res;
                }
            }
        }
        return res;
    }
    void numIslandsDFS(vector > &grid, vector > &visited, int x, int y) {
        if (x < 0 || x >= grid.size()) return;
        if (y < 0 || y >= grid[0].size()) return;
        if (grid[x][y] != '1' || visited[x][y]) return;
        visited[x][y] = true;
        numIslandsDFS(grid, visited, x - 1, y);
        numIslandsDFS(grid, visited, x + 1, y);
        numIslandsDFS(grid, visited, x, y - 1);
        numIslandsDFS(grid, visited, x, y + 1);
    }
};

值得学习的地方至少有两个,首先结构更清晰,把判断都放在一起,放在最前面,递归部分在后。这样确实更清楚明了。还有就是visited这个存在,我很随意的用int作为基础数据类型,非常没有必要,很占空间,用bool就刚好。

这题也可以用广度优先:

class Solution {
public:
    int numIslands(vector>& grid) {
        int res = 0;
        int nrow = grid.size();
        if (nrow < 1) return res;
        int ncol = grid[0].size();
        
        vector> isVisited(nrow, vector(ncol, false));
        queue> q;
        for (int i = 0; i < nrow; i++) {
            for (int j = 0; j < ncol; j++) {
                if (grid[i][j] == '1' && isVisited[i][j] == false) {
                    res++;
                    q.push({i, j});
                    while (!q.empty()) {
                        auto index = q.front();
                        q.pop();
                        int r = index.first;
                        int c = index.second;
                        isVisited[r][c] = true;
                        if (r - 1 >= 0 && grid[r - 1][c] == '1' && isVisited[r - 1][c] == false) q.push({r - 1, c});
                        if (r + 1 < nrow && grid[r + 1][c] == '1' && isVisited[r + 1][c] == false) q.push({r + 1, c});
                        if (c - 1 >= 0 && grid[r][c - 1] == '1' && isVisited[r][c - 1] == false) q.push({r, c - 1});
                        if (c + 1 < ncol && grid[r][c + 1] == '1' && isVisited[r][c + 1] == false) q.push({r, c + 1});
                    }
                }
            }
        }
        
        return res;
    }
};

但是这个答案过不了,不管是时间还是空间,都会消耗过多。理论上深度优先和广度优先效率上没有很大差异的。这里的问题很有意思。因为广度优先里把未访问的点先放到queue里存着,一个点会是多个点的邻居,会被放多次,第一个pop出的时候,被访问,检查四个邻居,第二次又被pop出的时候,其实不应该再讨论这个点了,但我没有在这里加限制,我看上去在push前作了检查,却没有想到queue里的状态会发生变化。上面代码加一句话就行。

class Solution {
public:
    int numIslands(vector>& grid) {
        int res = 0;
        int nrow = grid.size();
        if (nrow < 1) return res;
        int ncol = grid[0].size();
        
        vector> isVisited(nrow, vector(ncol, false));
        queue> q;
        for (int i = 0; i < nrow; i++) {
            for (int j = 0; j < ncol; j++) {
                if (grid[i][j] == '1' && isVisited[i][j] == false) {
                    res++;
                    q.push({i, j});
                    while (!q.empty()) {
                        auto index = q.front();
                        q.pop();
                        int r = index.first;
                        int c = index.second;
                        if (isVisited[r][c] == true) continue;   // very important
                        isVisited[r][c] = true;
                        if (r - 1 >= 0 && grid[r - 1][c] == '1' && isVisited[r - 1][c] == false) q.push({r - 1, c});
                        if (r + 1 < nrow && grid[r + 1][c] == '1' && isVisited[r + 1][c] == false) q.push({r + 1, c});
                        if (c - 1 >= 0 && grid[r][c - 1] == '1' && isVisited[r][c - 1] == false) q.push({r, c - 1});
                        if (c + 1 < ncol && grid[r][c + 1] == '1' && isVisited[r][c + 1] == false) q.push({r, c + 1});
                    }
                }
            }
        }
        
        return res;
    }
};

你可能感兴趣的:(leetcode,algorithm)