KamaCoder 99. 岛屿数量 + Leetcode 200. Number of Islands

99. 岛屿数量

题目描述:

给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。

输入描述:

第一行包含两个整数 N, M,表示矩阵的行数和列数。

后续 N 行,每行包含 M 个数字,数字为 1 或者 0。

输出描述:

输出一个整数,表示岛屿的数量。如果不存在岛屿,则输出 0。

输入示例:

根据测试案例中所展示,岛屿数量共有 3 个,所以输出 3。

思路

深度优先搜索

注意题目中每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

也就是说斜角度链接是不算了, 例如示例二,是三个岛屿,如图:

考虑遇到一个没有访问过的节点陆地,计数器就加1,然后把该节点陆地所能遍历到的陆地都标记上。

再遇到标记过的陆地节点和海洋节点的时候直接跳过。这样就得到了岛屿的最终数量。

广度优先搜索

这里有一个广搜中很重要的细节:

根本原因是只要 加入队列就代表 走过,就需要标记,而不是从队列拿出来的时候再去标记走过

如果从队列拿出节点,再去标记这个节点走过,就会发生下图所示的结果,会导致很多节点重复加入队列。

代码

C++深度优先搜索(DFS这里只起到标记位置的作用,一次找出整个岛)

#include <iostream>
#include <vector>
using namespace std;

int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
void dfs(const vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {
    for (int i = 0; i < 4; ++i) {
        int nextx = x + dir[i][0];
        int nexty = y + dir[i][1];
        if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) {
            continue; // 越界了,直接跳过
        }
        if (!visited[nextx][nexty] && grid[nextx][nexty] == 1) {
            // 没有访问过,同时是陆地
            visited[nextx][nexty] = true;
            dfs(grid, visited, nextx, nexty);
        }
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> grid(n, vector<int>(m, 0));
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            cin >> grid[i][j];
        }
    }
    
    vector<vector<bool>> visited(n, vector<bool>(m, false));
    
    int result = 0;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            if (!visited[i][j] && grid[i][j] == 1) {
                visited[i][j] = true;
                result++;
                dfs(grid, visited, i, j); // 将与其链接的岛屿都标记上true
            }
        }
    }
    
    cout << result << endl;
}

C++广度优先搜索(把同一个岛屿的遍历在一个BFS内完成)

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
void bfs(const vector<vector<int>>& grid, vector<vector<bool>>& visited, int x, int y) {
    queue<pair<int, int>> que;
    que.push({x, y});
    visited[x][y] = true;
    while (!que.empty()) {
        pair<int, int> cur = que.front(); que.pop();
        int curx = cur.first;
        int cury = cur.second;
        for (int i = 0; i < 4; ++i) {
            int nextx = curx + dir[i][0];
            int nexty = cury + dir[i][1];
            if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;
            if (!visited[nextx][nexty] && grid[nextx][nexty] == 1) {
                que.push({nextx, nexty}); // 压进队列,之后再检查。而不是像DFS一样,一路走到底。(没有BFS的套用)
                visited[nextx][nexty] = true; // 只要压进队列立刻标记
            }
        }
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> grid(n, vector<int>(m, 0));
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            cin >> grid[i][j];
        }
    }
    
    vector<vector<bool>> visited(n, vector<bool>(m, false));
    
    int result = 0;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            if (!visited[i][j] && grid[i][j] == 1) {
                visited[i][j] = true;
                result++; // 结果再进入BFS之前累加,因为找到了新岛屿
                bfs(grid, visited, i, j); // 将与其链接的岛屿都标记上true
            }
        }
    }
    
    cout << result << endl;
}

Python深度优先搜索

from collections import deque

dir = [(0, 1), (1, 0), (0, -1), (-1, 0)]

def dfs(grid, visited, x, y):
    for dx, dy in dir:
        nextx, nexty = x + dx, y + dy
        if nextx < 0 or nextx >= len(grid) or nexty < 0 or nexty >= len(grid[0]):
            continue
        if grid[nextx][nexty] == 1 and not visited[nextx][nexty]:
            visited[nextx][nexty] = True
            dfs(grid, visited, nextx, nexty)
        

def main():
    n, m = map(int, input().split())
    grid = [list(map(int, input().split())) for _ in range(n)] # 'map'函数返回的是一个迭代器,而不是一个列表。为了将其转换为列表,我们使用 list() 函数将迭代器转化为一个具体的列表。
    visited = [[False] * (m) for _ in range(n)]
            
    result = 0
    for i in range(n):
        for j in range(m):
            if (grid[i][j] == 1 and not visited[i][j]):
                result += 1
                visited[i][j] = True
                dfs(grid, visited, i, j)
                
    print(result)
    
if __name__ == "__main__":
    main()

Python广度优先搜索

from collections import deque

dir = [(0, 1), (1, 0), (0, -1), (-1, 0)]

def bfs(grid, visited, x, y):
    queue = deque([(x, y)])
    visited[x][y] = True
    while (queue):
        curx, cury = queue.popleft()
        for dx, dy in dir:
            nextx, nexty = curx + dx, cury + dy
            if nextx < 0 or nextx >= len(grid) or nexty < 0 or nexty >= len(grid[0]): # 注意这里从0开始所以比n,m小1,如果等于的时候实际上已经越界
                continue
            if not visited[nextx][nexty] and grid[nextx][nexty] == 1:
                queue.append((nextx, nexty))
                visited[nextx][nexty] = True

def main():
    n, m = map(int, input().split())
    grid = [list(map(int, input().split())) for _ in range(n)] # 'map'函数返回的是一个迭代器,而不是一个列表。为了将其转换为列表,我们使用 list() 函数将迭代器转化为一个具体的列表。
    visited = [[False] * (m) for _ in range(n)]
            
    result = 0
    for i in range(n):
        for j in range(m):
            if (grid[i][j] == 1 and not visited[i][j]):
                result += 1
                visited[i][j] = True
                bfs(grid, visited, i, j)
                
    print(result)
    
if __name__ == "__main__":
    main()

Leetcode 200. Number of Islands

C++广度优先搜索 (字符用单引号,字符串用双引号)

#include <iostream>
#include <vector>
#include <queue>
using namespace std;
class Solution {
public:
    int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
    void bfs(const vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {
        queue<pair<int, int>> que;
        que.push({x, y});
        visited[x][y] = true;
        while (!que.empty()) {
            pair<int, int> cur = que.front(); que.pop();
            int curx = cur.first;
            int cury = cur.second;
            for (int i = 0; i < 4; ++i) {
                int nextx = curx + dir[i][0];
                int nexty = cury + dir[i][1];
                if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;
                if (!visited[nextx][nexty] && grid[nextx][nexty] == '1') {
                    que.push({nextx, nexty}); // 压进队列,之后再检查。而不是像DFS一样,一路走到底。(没有BFS的套用)
                    visited[nextx][nexty] = true; // 只要压进队列立刻标记
                }
            }
        }
    }

    int numIslands(vector<vector<char>>& grid) {
        int n = grid.size();
        int m = grid[0].size();
        vector<vector<bool>> visited(n, vector<bool>(m, false));
    
        int result = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (!visited[i][j] && grid[i][j] == '1') {
                    visited[i][j] = true;
                    result++; // 结果再进入BFS之前累加,因为找到了新岛屿
                    bfs(grid, visited, i, j); // 将与其链接的岛屿都标记上true
                }
            }
        }

        return result;
    }
};

Python深度优先搜索

class Solution:
    dir = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    def dfs(self, grid, visited, x, y):
        for dx, dy in self.dir:
            nextx, nexty = x + dx, y + dy
            if nextx < 0 or nextx >= len(grid) or nexty < 0 or nexty >= len(grid[0]):
                continue
            if grid[nextx][nexty] == '1' and not visited[nextx][nexty]:
                visited[nextx][nexty] = True
                self.dfs(grid, visited, nextx, nexty)

    def numIslands(self, grid: List[List[str]]) -> int:
        n, m = len(grid), len(grid[0])

        visited = [[False] * (m) for _ in range(n)]
            
        result = 0
        for i in range(n):
            for j in range(m):
                if (grid[i][j] == '1' and not visited[i][j]):
                    result += 1
                    visited[i][j] = True
                    self.dfs(grid, visited, i, j)
        return result

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值