返回

水位上升的泳池中游泳--LeetCode 困难难度 题目分享

前端

题目链接

水位上升的泳池中游泳

题目

在一个大小为 n x n 的网格中,每个单元格可以是以下三种状态之一:

  • 0 表示这个单元格是空的。
  • 1 表示这个单元格是部分水淹的。
  • 2 表示这个单元格是完全水淹的。

一开始,这 n x n 的网格中,只有最左上角的单元格是部分水淹的。而其他所有单元格都是空的。

水会从部分水淹的单元格流向四周相邻的空单元格。每个单元格的水最多可以向四周相邻的四个单元格流去。
当一个单元格的水流向四周相邻的单元格时,它自己的水位将会下降。

如果一个单元格的水位降到 0,那么这个单元格将变成空的。

如果一个单元格的水位上升到 2,那么这个单元格将变成完全水淹的。

我们用一个数组 heights 来表示整个网格。其中:

  • heights[i][j] 表示坐标 (i, j) 单元格的水位高度。
  • 如果 heights[i][j] 等于 0 那么坐标 (i, j) 单元格是空的。
  • 如果 heights[i][j] 等于 1 那么坐标 (i, j) 单元格是部分水淹的。
  • 如果 heights[i][j] 等于 2 那么坐标 (i, j) 单元格是完全水淹的。

您需要返回一个整数 time ,表示网格中最后一个小于或等于 1 的单元格完全水淹所需的时间。

示例

示例 1:

输入:heights = [[0,2,1,0],[0,1,0,1],[1,1,1,2],[0,1,2,2]]
输出:3
解释:
0 2 1 0
0 1 0 1
1 1 1 2
0 1 2 2
初始时,网格中只有最左上角的单元格是部分水淹的。
在第一回合中,水流向四周相邻的空单元格,所以以下单元格的水位将会发生变化:
1 2 2 0
1 2 2 1
1 2 2 2
0 1 2 2
在第二回合中,水流向四周相邻的空单元格,所以以下单元格的水位将会发生变化:
2 2 2 0
2 2 2 1
2 2 2 2
0 1 2 2
在第三回合中,水流向四周相邻的空单元格,所以以下单元格的水位将会发生变化:
2 2 2 0
2 2 2 1
2 2 2 2
0 1 2 2
因此,网格中最后一个小于或等于 1 的单元格在第 3 回合中被完全水淹。

示例 2:

输入:heights = [[3,2,3],[0,0,0],[0,0,0]]
输出:4
解释:
3 2 3
0 0 0
0 0 0
初始时,网格中只有最左上角和最右上角的单元格是部分水淹的。
在第一回合中,水流向四周相邻的空单元格,所以以下单元格的水位将会发生变化:
2 3 3
1 1 1
0 0 0
在第二回合中,水流向四周相邻的空单元格,所以以下单元格的水位将会发生变化:
2 3 3
2 2 2
1 1 0
在第三回合中,水流向四周相邻的空单元格,所以以下单元格的水位将会发生变化:
2 3 3
2 3 2
2 2 1
在第四回合中,水流向四周相邻的空单元格,所以以下单元格的水位将会发生变化:
3 3 3
3 3 3
3 3 2
因此,网格中最后一个小于或等于 1 的单元格在第 4 回合中被完全水淹。

示例 3:

输入:heights = [[0,1,2,3,4],[2,3,4,5,6],[1,2,3,4,5],[0,1,2,3,4],[0,1,2,3,4]]
输出:16
解释:
0 1 2 3 4
2 3 4 5 6
1 2 3 4 5
0 1 2 3 4
0 1 2 3 4
初始时,网格中有 9 个单元格是部分水淹的。
在第 16 回合中,最后一个小于或等于 1 的单元格被完全水淹。

算法

步骤一:建堆

我们首先将网格中所有部分水淹的单元格的高度值保存到一个最小堆中。最小堆是一个数据结构,它将最小的元素放在堆顶。

import heapq

class Cell:
    def __init__(self, x, y, height):
        self.x = x
        self.y = y
        self.height = height

    def __lt__(self, other):
        return self.height < other.height

def build_heap(heights):
    heap = []
    for i in range(len(heights)):
        for j in range(len(heights[0])):
            if heights[i][j] == 1:
                heapq.heappush(heap, Cell(i, j, heights[i][j]))
    return heap

步骤二:开始遍历

我们将从最小堆的堆顶开始遍历。对于堆顶的单元格,我们将检查它的四个相邻单元格。如果相邻单元格是空的,我们将把相邻单元格的高度值添加到堆中。如果相邻单元格是部分水淹的,我们将更新相邻单元格的高度值。

def swim_in_rising_water(heights):
    heap = build_heap(heights)
    time = 0
    while heap:
        cell = heapq.heappop(heap)
        time = max(time, cell.height)
        # 检查四个相邻单元格
        if cell.x > 0 and heights[cell.x - 1][cell.y] != 2:
            heights[cell.x - 1][cell.y] = max(heights[cell.x - 1][cell.y], cell.height + 1)
            heapq.heappush(heap, Cell(cell.x - 1, cell.y, heights[cell.x - 1][cell.y]))
        if cell.x < len(heights) - 1 and heights[cell.x + 1][cell.y] != 2:
            heights[cell.x + 1][cell.y] = max(heights[cell.x + 1][cell.y], cell.height + 1)
            heapq.heappush(heap, Cell(cell.x + 1, cell.y, heights[cell.x + 1][cell.y]))
        if cell.y > 0 and heights[cell.x][cell.y - 1] != 2:
            heights[cell.x][cell.y - 1] = max(heights[cell.x][cell.y - 1], cell.height + 1)
            heapq.heappush(heap, Cell(cell.x, cell.y - 1, heights[cell.x][cell.y - 1]))
        if cell.y < len(heights[0]) - 1 and heights[cell.x][cell.y + 1] != 2:
            heights[cell.x][cell.y + 1]