代码随想录算法训练营第五十六天| 图论2—卡码网99. 岛屿数量(dfs & bfs)

假期归来继续刷题,图论第二天,主要是进一步熟悉dfs 和 bfs 的运用。

99. 岛屿数量(dfs)

99. 岛屿数量

ACM模式还是需要练,不过现在输入输出的感觉已经比较熟悉了。首先是要按照输入搭建一个grid,然后有一个对应的全是False 的 visit。

关于方向就只有上下左右四个,如果可以走斜向,方向就变成八个了。递归的过程其实比较好理解,就是当前x,y逐步相加,如果越界了就continue,然后如果碰到了grid中为1但没有visit的,就变成visit继续向后递归,当四边都没法符合判断条件的话就进行返回,这就是dfs顺着一条路走下去的思想。

然后是主函数中的调用,当碰到第一个符合条件的地块开始,并计数,记得同时将这块变为True,因为dfs函数里直接是从下一个地块开始转换的。然后不停递归,当结束的时候,就继续回到主函数的遍历中,去测下一个符合if grid[i][j] == 1 and not visited[i][j]:条件的地块,当碰到就是第二块岛,记得将数量+1然后继续递归。

简单理解,主函数中,i,j二次遍历,一旦找到一个为1的地块便计数+1,同时dfs开始,当dfs遍历完之后,i,j继续遍历,这时候如果遍历到之前dfs遍历的地块,也会因为visit中为True而不会开始dfs。可以想象成发现一个起点,dfs开始逐步扩散发掘所有连着的地块。

python 复制代码
# dfs方法一
direction = [[0, 1], [1, 0], [0, -1], [-1, 0]] 

def dfs(grid, visited, x, 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 = 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):
            # 判断:如果当前节点是陆地,res+1并标记访问该节点,使用深度搜索标记相邻陆地。
            if grid[i][j] == 1 and not visited[i][j]:
                res += 1
                visited[i][j] = True
                dfs(grid, visited, i, j)
    
    print(res)

dfs的版本二,变化不大,总体方法更符合之前回溯的模板,即参数-终止条件-单层逻辑。

版本一的写法是 :下一个节点是否能合法已经判断完了,传进dfs函数的就是合法节点。

版本二的写法是:不管节点是否合法,上来就dfs,然后在终止条件的地方进行判断,不合法再return。

理论上来讲,版本一的效率更高一些,因为避免了 没有意义的递归调用,在调用dfs之前,就做合法性判断。 但从写法来说,可能版本二 更利于理解一些。(不过其实都差不太多)

python 复制代码
direction = [[0, 1], [1, 0], [0, -1], [-1, 0]] 

def dfs(grid, visited, x, y):
    # 与版本一的差别,在调用前增加判断终止条件
    if visited[x][y] or grid[x][y] == 0:
        return
    visited[x][y] = True

    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
        dfs(grid, visited, next_x, next_y)


if __name__ == '__main__':
    # 版本二
    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):
            # 判断:如果当前节点是陆地,res+1并标记访问该节点,使用深度搜索标记相邻陆地。
            if grid[i][j] == 1 and not visited[i][j]:
                res += 1
                dfs(grid, visited, i, j)

    print(res)

99. 岛屿数量(bfs)

深搜是一条路走到头,广搜则是一圈一圈的扩散,可以类比为二叉树的层序遍历,原本是每个节点有左右两个子节点,现在变成每个地块有上下左右四个地块。

在bfs函数里,记住每开始一次bfs,要重置一次que,然后将当前的地块x,y 加入队列,并在visit中变成True。之后便是弹出,符合条件加入,重复直到队列为空。

之后主函数调用则是一样的思路,类似发现一个起点,然后一圈一圈开始扩散,直到无法扩散,便开始遍历寻找下一个岛屿的起点。

python 复制代码
from collections import deque
directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]
def bfs(grid, visited, x, y):
    que = deque([])
    que.append([x,y])
    visited[x][y] = True
    while que:
        cur_x, cur_y = que.popleft()
        for i, j in directions:
            next_x = cur_x + i
            next_y = cur_y + j
            if next_y < 0 or next_x < 0 or next_x >= len(grid) 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
                que.append([next_x, next_y])
 
 
if __name__ == "__main__":
    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
                bfs(grid, visited, i, j)
    print(res)
 
相关推荐
JK0x077 分钟前
代码随想录算法训练营 Day37 动态规划Ⅴ 完全背包 零钱兑换
算法·动态规划
weixin_4640780713 分钟前
.NET 多线程题目汇总
算法·.net
纪元A梦16 分钟前
贪心算法应用:边着色问题详解
java·算法·贪心算法
王燕龙(大卫)1 小时前
递归下降算法
开发语言·c++·算法
AI是这个时代的魔法1 小时前
The Action Replay Process
数学·算法·随机决策过程
郭涤生1 小时前
C++ 完美转发
c++·算法
Codeking__2 小时前
滑动窗口——无重复字符最长的字串
算法·哈希算法
Mi Manchi263 小时前
力扣热题100之反转链表
算法·leetcode·链表
n33(NK)3 小时前
【算法基础】选择排序算法 - JAVA
数据结构·算法·排序算法
CS创新实验室3 小时前
408考研逐题详解:2009年第6题
数据结构·考研·算法·408·真题·计算机考研·408计算机