代码随想录训练营 Day51打卡 图论part02 99. 岛屿数量 100. 岛屿的最大面积

代码随想录训练营 Day51打卡 图论part02

一、卡码99. 岛屿数量

题目描述

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

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

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

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

4 5

1 1 0 0 0

1 1 0 0 0

0 0 1 0 0

0 0 0 1 1
输出示例

3
提示信息

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

核心步骤:

深度优先搜索 (DFS):当找到一块未访问的陆地时,使用 DFS 遍历所有与它相邻的陆地,并标记为已访问。DFS 会递归地访问所有四个方向上的相邻陆地。

计数岛屿:每找到一个新的未访问的陆地,岛屿数加一,同时使用 DFS 标记所有相邻的陆地,防止重复计数。

边界检查:每次访问新的坐标时,需要确保坐标合法(不越界)且是未访问的陆地。

DFS

python 复制代码
# 定义四个方向:上、右、下、左
direction = [[0, 1], [1, 0], [0, -1], [-1, 0]]  # 上右下左四个方向

def dfs(grid, visited, x, y):
    """
    对一块陆地进行深度优先遍历并标记
    :param grid: 二维网格,1 代表陆地,0 代表水
    :param visited: 记录哪些节点被访问过
    :param x: 当前节点的行索引
    :param y: 当前节点的列索引
    """
    for i, j in direction:
        next_x = x + i
        next_y = y + j
        # 判断坐标是否越界
        if next_x < 0 or next_x >= len(grid) or next_y < 0 or next_y >= len(grid[0]):
            continue  # 越界直接跳过
        # 如果是未访问的陆地,进行递归遍历
        if not visited[next_x][next_y] and grid[next_x][next_y] == 1:
            visited[next_x][next_y] = True  # 标记为已访问
            dfs(grid, visited, next_x, next_y)  # 递归调用,继续深度遍历

if __name__ == '__main__':
    # 输入网格的大小:n 表示行数,m 表示列数
    n, m = map(int, input().split())
    
    # 构建网格 (邻接矩阵表示法)
    grid = []
    for i in range(n):
        grid.append(list(map(int, input().split())))  # 每行输入网格

    # 初始化访问表,标记哪些节点已访问过
    visited = [[False] * m for _ in range(n)]
    
    # 岛屿计数结果
    res = 0
    # 遍历网格的每个点
    for i in range(n):
        for j in range(m):
            # 如果当前点是未访问的陆地
            if grid[i][j] == 1 and not visited[i][j]:
                res += 1  # 找到一个新的岛屿,岛屿数加 1
                visited[i][j] = True  # 标记为已访问
                dfs(grid, visited, i, j)  # 对该点进行深度优先搜索,标记相邻的陆地

    # 输出岛屿的数量
    print(res)

BFS 实现思路:

  1. 队列
    (Queue):使用队列来保存当前层需要访问的节点,每次从队列中取出一个节点,将其所有相邻的未访问陆地加入队列,直到所有与该节点相连的陆地都遍历完。
  2. 邻接矩阵表示:同样使用二维数组(邻接矩阵)表示网格,1 表示陆地,0 表示水。
  3. 计数岛屿:每次找到一个新的未访问陆地时,岛屿数量加 1,使用 BFS 来遍历整个岛屿,确保该岛屿上的所有陆地都被标记为已访问。

BFS

python 复制代码
from collections import deque

# 定义四个方向:上、右、下、左
direction = [[0, 1], [1, 0], [0, -1], [-1, 0]]  # 上、右、下、左

def bfs(grid, visited, x, y):
    """
    使用 BFS 遍历和标记岛屿
    :param grid: 二维网格,1 代表陆地,0 代表水
    :param visited: 记录哪些节点被访问过
    :param x: 起点的行索引
    :param y: 起点的列索引
    """
    # 初始化一个队列,将起点加入队列并标记为已访问
    queue = deque()
    queue.append((x, y))
    visited[x][y] = True  # 标记起点已访问

    # 开始广度优先搜索
    while queue:
        cur_x, cur_y = queue.popleft()  # 从队列中取出当前节点
        
        # 遍历当前节点的四个相邻方向
        for i, j in direction:
            next_x = cur_x + i
            next_y = cur_y + j
            # 判断是否越界以及是否是未访问的陆地
            if 0 <= next_x < len(grid) and 0 <= next_y < len(grid[0]):
                if not visited[next_x][next_y] and grid[next_x][next_y] == 1:
                    # 如果是未访问的陆地,加入队列并标记为已访问
                    visited[next_x][next_y] = True
                    queue.append((next_x, next_y))

if __name__ == '__main__':
    # 输入网格的大小:n 表示行数,m 表示列数
    n, m = map(int, input().split())
    
    # 构建网格 (邻接矩阵表示法)
    grid = [list(map(int, input().split())) for _ in range(n)]

    # 初始化访问表,标记哪些节点已访问过
    visited = [[False] * m for _ in range(n)]
    
    # 岛屿计数结果
    res = 0
    # 遍历网格的每个点
    for i in range(n):
        for j in range(m):
            # 判断:如果当前节点是未访问的陆地
            if grid[i][j] == 1 and not visited[i][j]:
                res += 1  # 找到一个新的岛屿,岛屿数加 1
                bfs(grid, visited, i, j)  # 使用 BFS 搜索并标记该岛屿

    # 输出岛屿的数量
    print(res)

总结

  • BFS 通过使用队列逐层访问相邻节点,非常适合处理需要按层次逐步扩展的搜索问题。
  • DFS 适合更深层次的递归搜索,而 BFS 更注重广度、层次上的扩展。对于岛屿计数问题,BFS 和 DFS都可以高效解决,关键在于如何标记已访问的节点,防止重复计数。

题目链接
题目文章讲解

二、卡码100. 岛屿的最大面积

题目描述

给定一个由 1(陆地)和 0(水)组成的矩阵,计算岛屿的最大面积。岛屿面积的计算方式为组成岛屿的陆地的总数。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。
输入描述

第一行包含两个整数 N, M,表示矩阵的行数和列数。后续 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述

输出一个整数,表示岛屿的最大面积。如果不存在岛屿,则输出 0。
输入示例

4 5

1 1 0 0 0

1 1 0 0 0

0 0 1 0 0

0 0 0 1 1
输出示例

4
提示信息

样例输入中,岛屿的最大面积为 4。

主要步骤:

  1. 深度优先搜索 (DFS):对于每块未访问的陆地(grid[i][j] == 1 且 visited[i][j] == False),使用DFS 遍历所有与它相连的陆地块,并统计连通区域的大小。DFS 递归遍历四个方向,确保所有相连的陆地都被访问。
  2. 计数连通陆地的面积:每次通过 DFS 遍历完一块连通的陆地块后,记录该区域的大小,并在所有遍历完成后输出最大的区域面积。
  3. 全局变量 count:在 DFS 中使用全局变量 count 来记录当前遍历到的连通陆地块的大小。每次发现一块新陆地时,count 从1 开始计数,DFS 过程中每找到一块相邻的陆地块,count 增加 1。

代码实现

python 复制代码
# 定义四个方向:上、右、下、左
position = [[0, 1], [1, 0], [0, -1], [-1, 0]]
count = 0  # 全局变量,用于记录当前连通陆地的面积

def dfs(grid, visited, x, y):
    """
    深度优先搜索,遍历并标记一整块连通的陆地
    :param grid: 二维网格,1 代表陆地,0 代表水
    :param visited: 记录哪些节点被访问过
    :param x: 当前节点的行索引
    :param y: 当前节点的列索引
    """
    global count  # 使用全局变量 count 记录当前连通区域的面积
    for i, j in position:  # 遍历四个方向:上、右、下、左
        cur_x = x + i
        cur_y = y + j
        # 判断坐标是否越界
        if cur_x < 0 or cur_x >= len(grid) or cur_y < 0 or cur_y >= len(grid[0]):
            continue  # 如果越界,跳过该方向
        # 如果当前节点是未访问的陆地块,继续递归遍历
        if not visited[cur_x][cur_y] and grid[cur_x][cur_y] == 1:
            visited[cur_x][cur_y] = True  # 标记为已访问
            count += 1  # 当前连通陆地面积加 1
            dfs(grid, visited, cur_x, cur_y)  # 递归搜索相邻的陆地块

# 主函数,读取输入并处理
n, m = map(int, input().split())  # 输入网格的大小 n 行 m 列
# 构建网格,读取每行输入作为网格的一部分
grid = []
for i in range(n):
    grid.append(list(map(int, input().split())))  # 每行输入陆地/水域信息
# 初始化访问数组,记录哪些节点已访问过
visited = [[False] * m for _ in range(n)]

result = 0  # 记录所有连通陆地块中的最大面积
# 遍历整个网格
for i in range(n):
    for j in range(m):
        # 如果当前节点是未访问的陆地块,开始新的 DFS 遍历
        if grid[i][j] == 1 and not visited[i][j]:
            count = 1  # 初始化当前连通区域的面积为 1
            visited[i][j] = True  # 标记当前节点为已访问
            dfs(grid, visited, i, j)  # 使用 DFS 遍历相连的陆地块
            result = max(count, result)  # 更新最大的连通区域面积

# 输出结果,最大连通陆地面积
print(result)

题目链接
题目文章讲解

相关推荐
云卓SKYDROID13 分钟前
除草机器人算法以及技术详解!
算法·机器人·科普·高科技·云卓科技·算法技术
半盏茶香37 分钟前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
徐子童41 分钟前
双指针算法习题解答
算法
想要打 Acm 的小周同学呀1 小时前
LRU缓存算法
java·算法·缓存
劲夫学编程2 小时前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪2 小时前
孤岛的总面积(Dfs C#
算法·深度优先
浮生如梦_4 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
励志成为嵌入式工程师6 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉6 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer6 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法