中等题:病毒在封闭空间中的传播时间 | 豆包MarsCode AI刷题

234 阅读6分钟

1、问题

1.1 问题描述

在一个封闭的房间中,排列着 n 行 m 列的座位,每个座位间距为 1 米。房间中每个座位上都坐着一人,部分人戴了口罩,部分人未戴口罩。已知房间中有一位已经感染病毒的人,病毒可以每秒向相邻座位传播 1 米。对于戴口罩的人,病毒需要两秒才能成功感染,或者需要在一秒内从两个相邻的感染者处同时被感染。设计一个算法,计算病毒感染房间内所有人所需的最短时间。

1.2 测试样例

样例1:

输入:row_n = 4, column_m = 4, seats = [[0, 1, 1, 1], [1, 0, 1, 0], [1, 1, 1, 1], [0, 0, 0, 1]], patient = [2, 2]
输出:6

样例2:

输入:row_n = 3, column_m = 3, seats = [[0, 0, 0], [0, 1, 0], [0, 0, 0]], patient = [2, 2]
输出:4

样例3:

输入:row_n = 5, column_m = 5, seats = [[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 1, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]], patient = [3, 3]
输出:7

2、思路

本题的核心在于模拟病毒在房间中的传播过程。我们需要计算病毒感染房间内所有人所需的最短时间。病毒的传播规则如下:

  • 未戴口罩的人:病毒可以在1秒内感染相邻的未戴口罩的人。
  • 戴口罩的人:病毒需要2秒才能成功感染,或者需要在一秒内从两个相邻的感染者处同时被感染。

为了实现这一过程,我们可以使用广度优先搜索(BFS)算法。BFS算法能够有效地模拟病毒的传播过程,并且能够保证在每一秒内处理所有当前感染者的相邻座位。

具体步骤如下:

  • 初始化:将初始感染者的位置加入队列,并将该位置标记为已感染(值设为-1)。
  • BFS传播:在每一秒内,处理队列中的所有当前感染者,尝试向四个方向(上、下、左、右)传播病毒。
  • 更新状态:对于每个相邻的座位,如果该座位是未感染的(值为0),则将其加入队列;如果该座位是戴口罩的(值为1),则减少其值。
  • 终止传播:当队列中的元素数量等于矩阵中的总座位数时,表示所有座位都已被感染,结束循环。

2.1 初始化

首先,我们需要初始化一些变量,包括时间计数器 time,感染源的坐标 x 和 y,以及一个队列 q 用于存储当前感染的座位。此外,在开始传播病毒之前,我们需要检查感染源是否在矩阵范围内。如果不在范围内,直接返回时间 0

time = 0  # 初始化时间计数器
x = patient[0]  # 获取感染源的行坐标
y = patient[1]  # 获取感染源的列坐标

# 检查感染源是否在矩阵范围内
if x < 0 or x > row_n - 1 or y < 0 or y > column_m - 1:
    return time  # 如果不在范围内,直接返回0

# 初始化队列,将感染源加入队列
q = [[x, y]]
# 将感染源位置的值设为-1,表示已感染
seats[x][y] = -1

2.2 BFS传播

使用BFS算法来模拟病毒的传播过程。每次从队列中取出一个座位,检查其四个相邻座位是否可以被感染。如果相邻座位是未感染的(值为 0),则将其加入队列;如果相邻座位是戴口罩的(值为 1),则减少其值。

while len(q) != row_n * column_m:
    old_len = len(q)  # 记录当前队列的长度
    for i in range(old_len):
        now_x = q[i][0]  # 获取当前处理元素的行坐标
        now_y = q[i][1]  # 获取当前处理元素的列坐标

        # 尝试向四个方向传播病毒
        spread(now_x - 1, now_y, row_n, column_m, seats, q)
        spread(now_x + 1, now_y, row_n, column_m, seats, q)
        spread(now_x, now_y - 1, row_n, column_m, seats, q)
        spread(now_x, now_y + 1, row_n, column_m, seats, q)

    time += 1  # 每轮传播结束后,时间加1

2.3 更新状态

通过spread函数进行状态更新,它会检查当前位置 (x, y) 是否在矩阵范围内,并根据座位状态进行相应的处理。在每轮传播以及状态更新结束后,时间计数器 time 加 1

def spread(x, y, n, m, seats, queue):
    # 检查当前位置是否在矩阵范围内
    if 0 <= x <= n - 1 and 0 <= y <= m - 1:
        # 如果当前位置是未感染的(值为0),则将其加入队列
        if seats[x][y] == 0:
            queue.append([x, y])

        # 如果当前位置不是感染源(值不为-1),则减少其值
        if seats[x][y] != -1:
            seats[x][y] -= 1

2.4 终止传播

当队列中的元素数量等于矩阵中的总座位数时,表示所有座位都已被感染,那么停止传播。

3、代码

整体代码如下:

def spread(x, y, n, m, seats, queue):
    # 检查当前位置是否在矩阵范围内
    if 0 <= x <= n - 1 and 0 <= y <= m - 1:
        # 如果当前位置是未感染的(值为0),则将其加入队列
        if seats[x][y] == 0:
            queue.append([x, y])
            
        # 如果当前位置不是感染源(值不为-1),则减少其值
        if seats[x][y] != -1:
            seats[x][y] -= 1

def solution(row_n, column_m, seats, patient):
    time = 0  # 初始化时间计数器
    x = patient[0]  # 获取感染源的行坐标
    y = patient[1]  # 获取感染源的列坐标

    # 检查感染源是否在矩阵范围内
    if x < 0 or x > row_n - 1 or y < 0 or y > column_m - 1:
        return time  # 如果不在范围内,直接返回0

    # 初始化队列,将感染源加入队列
    q = [[x, y]]
    # 将感染源位置的值设为-1,表示已感染
    seats[x][y] = -1

    # 当队列中的元素数量不等于矩阵中的总座位数时,继续循环
    while len(q) != row_n * column_m:
        old_len = len(q)  # 记录当前队列的长度
        for i in range(old_len):
            now_x = q[i][0]  # 获取当前处理元素的行坐标
            now_y = q[i][1]  # 获取当前处理元素的列坐标

            # 尝试向四个方向传播病毒
            spread(now_x - 1, now_y, row_n, column_m, seats, q)
            spread(now_x + 1, now_y, row_n, column_m, seats, q)
            spread(now_x, now_y - 1, row_n, column_m, seats, q)
            spread(now_x, now_y + 1, row_n, column_m, seats, q)

        time += 1  # 每轮传播结束后,时间加1

    return time  # 返回总时间

4、运行结果

可以看到提交通过,说明我们的方法和代码都没有问题。 屏幕截图 2024-11-14 162057.png

5、总结分析

5.1 时间复杂度

  • 初始化:初始化时间计数器和队列的时间复杂度为 O(1)
  • BFS传播(包括了更新状态):每次传播时,我们需要遍历当前队列中的所有元素,并检查其相邻座位。在最坏情况下,每个座位都需要被检查一次,因此时间复杂度为 O(n * m)

5.2 空间复杂度

  • 队列:队列的空间复杂度为 O(n * m),因为最坏情况下所有座位都需要被存储在队列中。
  • 矩阵:矩阵的空间复杂度为 O(n * m)

该算法通过BFS模拟了病毒的传播过程,能够有效地计算出病毒感染房间内所有人所需的最短时间。算法的时间复杂度和空间复杂度均为 O(n * m)(其中 n 和 m 分别是矩阵的行数和列数),适用于大多数情况下的计算。