Skip to content

Commit

Permalink
更新题解列表
Browse files Browse the repository at this point in the history
  • Loading branch information
itcharge committed Nov 10, 2023
1 parent 9ec1a5b commit f1dfdd6
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 34 deletions.
54 changes: 47 additions & 7 deletions Solutions/0778. 水位上升的泳池中游泳.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,62 @@

## 题目大意

给定一个 `n * n` 大小的二维数组 `grid`,每一个方格的值 `grid[i][j]` 表示为位置 `(i, j)` 的高度。
**描述**给定一个 $n \times n$ 大小的二维数组 $grid$,每一个方格的值 $grid[i][j]$ 表示为位置 $(i, j)$ 的高度。

现在要从左上角 `(0, 0)` 位置出发,经过方格的一些点,到达右下角 `(n - 1, n - 1)` 位置上。其中所经过路径的花费为这条路径上所有位置的最大高度。
现在要从左上角 $(0, 0)$ 位置出发,经过方格的一些点,到达右下角 $(n - 1, n - 1)$ 位置上。其中所经过路径的花费为这条路径上所有位置的最大高度。

现在要求:计算从 `(0, 0)` 位置到 `(n - 1, n - 1)` 的最优路径的花费。
**要求**:计算从 $(0, 0)$ 位置到 $(n - 1, n - 1)$ 的最优路径的花费。

最优路径指的路径上最大高度最小的那条路径。
**说明**

- **最优路径**:路径上最大高度最小的那条路径。
- $n == grid.length$。
- $n == grid[i].length$。
- $1 \le n \le 50$。
- $0 \le grid[i][j] < n2$。
- $grid[i][j]$ 中每个值均无重复。

**示例**

- 示例 1:

![](https://assets.leetcode.com/uploads/2021/06/29/swim1-grid.jpg)

```python
输入: grid = [[0,2],[1,3]]
输出: 3
解释:
时间为 0 时,你位于坐标方格的位置为 (0, 0)。
此时你不能游向任意方向,因为四个相邻方向平台的高度都大于当前时间为 0 时的水位。
等时间到达 3 时,你才可以游向平台 (1, 1). 因为此时的水位是 3,坐标方格中的平台没有比水位 3 更高的,所以你可以游向坐标方格中的任意位置。
```

- 示例 2:

![](https://assets.leetcode.com/uploads/2021/06/29/swim2-grid-1.jpg)

```python
输入: grid = [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]]
输出: 16
解释: 最终的路线用加粗进行了标记。
我们必须等到时间为 16,此时才能保证平台 (0, 0) 和 (4, 4) 是连通的。
```

## 解题思路

### 思路 1:并查集

将整个网络抽象为一个无向图,每个点与相邻的点(上下左右)之间都存在一条无向边,边的权重为两个点之间的最大高度。

我们要找到左上角到右下角的最优路径,可以遍历所有的点,将所有的边存储到数组中,每条边的存储格式为 `[x, y, h]`,意思是编号 `x` 的点和编号为 `y` 的点之间的权重为 `h`
我们要找到左上角到右下角的最优路径,可以遍历所有的点,将所有的边存储到数组中,每条边的存储格式为 $[x, y, h]$,意思是编号 $x$ 的点和编号为 $y$ 的点之间的权重为 $h$

然后按照权重从小到大的顺序,对所有边进行排序。

再按照权重大小遍历所有边,将其依次加入并查集中。并且每次都需要判断 `(0, 0)` 点和 `(n - 1, n - 1)` 点是否连通。
再按照权重大小遍历所有边,将其依次加入并查集中。并且每次都需要判断 $(0, 0)$ 点和 $(n - 1, n - 1)$ 点是否连通。

如果连通,则该边的权重即为答案。

## 代码
### 思路 1:代码

```python
class UnionFind:
Expand Down Expand Up @@ -83,3 +118,8 @@ class Solution:
return 0
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(m \times n \times \alpha(m \times n))$,其中 $\alpha$ 是反 Ackerman 函数。
- **空间复杂度**:$O(m \times n)$。

86 changes: 72 additions & 14 deletions Solutions/0803. 打砖块.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,94 @@

## 题目大意

给定一个 `m * n` 大小的二元网格,其中 `1` 表示砖块,`0` 表示空白。砖块稳定(不会掉落)的前提是:
**描述**给定一个 $m \times n$ 大小的二元网格,其中 $1$ 表示砖块,$0$ 表示空白。砖块稳定(不会掉落)的前提是:

- 一块砖直接连接到网格的顶部。
- 或者至少有一块相邻(4 个方向之一)砖块稳定不会掉落时。

再给定一个数组 `hits`,这是需要依次消除砖块的位置。每当消除 `hits[i] = (row_i, col_i)` 位置上的砖块时,对应位置的砖块(若存在)会消失,然后其他的砖块可能因为这一消除操作而掉落。一旦砖块掉落,它会立即从网格中消失(即,它不会落在其他稳定的砖块上)。
再给定一个数组 $hits$,这是需要依次消除砖块的位置。每当消除 $hits[i] = (row_i, col_i)$ 位置上的砖块时,对应位置的砖块(若存在)会消失,然后其他的砖块可能因为这一消除操作而掉落。一旦砖块掉落,它会立即从网格中消失(即,它不会落在其他稳定的砖块上)。

要求:返回一个数组 `result`,其中 `result[i]` 表示第 `i` 次消除操作对应掉落的砖块数目。
**要求**:返回一个数组 $result$,其中 $result[i]$ 表示第 $i$ 次消除操作对应掉落的砖块数目。

注意:消除可能指向是没有砖块的空白位置,如果发生这种情况,则没有砖块掉落。
**说明**

- 消除可能指向是没有砖块的空白位置,如果发生这种情况,则没有砖块掉落。
- $m == grid.length$。
- $n == grid[i].length$。
- $1 \le m, n \le 200$。
- $grid[i][j]$ 为 $0$ 或 $1$。
- $1 \le hits.length \le 4 \times 10^4$。
- $hits[i].length == 2$。
- $0 \le xi \le m - 1$。
- $0 \le yi \le n - 1$。
- 所有 $(xi, yi)$ 互不相同。

**示例**

- 示例 1:

```python
输入:grid = [[1,0,0,0],[1,1,1,0]], hits = [[1,0]]
输出:[2]
解释:网格开始为:
[[1,0,0,0],
[1,1,1,0]]
消除 (1,0) 处加粗的砖块,得到网格:
[[1,0,0,0]
[0,1,1,0]]
两个加粗的砖不再稳定,因为它们不再与顶部相连,也不再与另一个稳定的砖相邻,因此它们将掉落。得到网格:
[[1,0,0,0],
[0,0,0,0]]
因此,结果为 [2]。
```

- 示例 2:

```python
输入:grid = [[1,0,0,0],[1,1,0,0]], hits = [[1,1],[1,0]]
输出:[0,0]
解释:网格开始为:
[[1,0,0,0],
[1,1,0,0]]
消除 (1,1) 处加粗的砖块,得到网格:
[[1,0,0,0],
[1,0,0,0]]
剩下的砖都很稳定,所以不会掉落。网格保持不变:
[[1,0,0,0],
[1,0,0,0]]
接下来消除 (1,0) 处加粗的砖块,得到网格:
[[1,0,0,0],
[0,0,0,0]]
剩下的砖块仍然是稳定的,所以不会有砖块掉落。
因此,结果为 [0,0]。
```

## 解题思路

### 思路 1:并查集

一个很直观的想法:

- 将所有砖块放入一个集合中。
- 根据 `hits` 数组的顺序,每敲掉一块砖。则将这块砖与相邻(4 个方向)的砖块断开集合。
- 根据 $hits$ 数组的顺序,每敲掉一块砖。则将这块砖与相邻(4 个方向)的砖块断开集合。
- 然后判断哪些砖块会掉落,从集合中删除会掉落的砖块,并统计掉落砖块的数量。
- `掉落砖块的数目 = 击碎砖块之前与屋顶相连的砖块数目 - 击碎砖块之后与屋顶相连的砖块数目 - 1`
- **掉落砖块的数目 = 击碎砖块之前与屋顶相连的砖块数目 - 击碎砖块之后与屋顶相连的砖块数目 - 1**

涉及集合问题,很容易想到用并查集来做。但是并查集主要用于合并查找集合,不适合断开集合。我们可以反向思考问题:

- 先将 `hits` 中的所有位置上的砖块敲掉。
- 先将 $hits$ 中的所有位置上的砖块敲掉。
- 将剩下的砖块建立并查集。
- 逆序填回被敲掉的砖块,并与相邻(4 个方向)的砖块合并。这样问题就变为了 `补上砖块会新增多少个砖块粘到屋顶`
- 逆序填回被敲掉的砖块,并与相邻(4 个方向)的砖块合并。这样问题就变为了 **补上砖块会新增多少个砖块粘到屋顶**

整个算法步骤具体如下:

- 先将二维数组 `grid` 复制一份到二维数组 `copy_gird` 上。这是因为遍历 `hits` 元素时需要判断原网格是空白还是被打碎的砖块。
-`copy_grid` 中将 `hits` 中打碎的砖块赋值为 `0`
- 建立并查集,将房顶上的砖块合并到一个集合中。
- 逆序遍历 `hits`,将 `hits` 中的砖块补到 `copy_grid` 中,并计算每一步中有多少个砖块粘到屋顶上(与屋顶砖块在一个集合中),并存入答案数组对应位置。
- 最后输出答案数组。
1. 先将二维数组 $grid$ 复制一份到二维数组 $copy\underline{}gird$ 上。这是因为遍历 $hits$ 元素时需要判断原网格是空白还是被打碎的砖块。
2.$copy\underline{}grid$ 中将 $hits$ 中打碎的砖块赋值为 $0$
3. 建立并查集,将房顶上的砖块合并到一个集合中。
4. 逆序遍历 $hits$,将 $hits$ 中的砖块补到 $copy\underline{}grid$ 中,并计算每一步中有多少个砖块粘到屋顶上(与屋顶砖块在一个集合中),并存入答案数组对应位置。
5. 最后输出答案数组。

## 代码
### 思路 1:代码

```python
class UnionFind:
Expand Down Expand Up @@ -119,3 +172,8 @@ class Solution:
return res
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(m \times n \times \alpha(m \times n))$,其中 $\alpha$ 是反 Ackerman 函数。
- **空间复杂度**:$O(m \times n)$。

12 changes: 6 additions & 6 deletions Solutions/0947. 移除最多的同行或同列石头.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

## 题目大意

**描述**:二维平面中有 `n` 块石头,每块石头都在整数坐标点上,且每个坐标点上最多只能有一块石头。如果一块石头的同行或者同列上有其他石头存在,那么就可以移除这块石头。
**描述**:二维平面中有 $n$ 块石头,每块石头都在整数坐标点上,且每个坐标点上最多只能有一块石头。如果一块石头的同行或者同列上有其他石头存在,那么就可以移除这块石头。

给你一个长度为 `n` 的数组 `stones` ,其中 `stones[i] = [xi, yi]` 表示第 `i` 块石头的位置。
给你一个长度为 $n$ 的数组 $stones$ ,其中 $stones[i] = [xi, yi]$ 表示第 $i$ 块石头的位置。

**要求**:返回可以移除的石子的最大数量。

Expand Down Expand Up @@ -51,9 +51,9 @@

题目「求最多可以移走的石头数目」也可以换一种思路:「求最少留下的石头数目」。

- 如果两个石头 `A``B` 处于同一行或者同一列,我们就可以删除石头 `A``B`,最少留下 `1` 个石头。
- 如果三个石头 `A``B``C`,其中 `A``B` 处于同一行,`B``C` 处于同一列,则我们可以先删除石头 `A`,再删除石头 `C`,最少留下 `1` 个石头。
- 如果有 `n` 个石头,其中每个石头都有一个同行或者同列的石头,则我们可以将 `n - 1` 个石头都删除,最少留下 `1` 个石头。
- 如果两个石头 $A$、$B$ 处于同一行或者同一列,我们就可以删除石头 $A$$B$,最少留下 $1$ 个石头。
- 如果三个石头 $A$、$B$、$C$,其中 $A$、$B$ 处于同一行,$B$、$C$ 处于同一列,则我们可以先删除石头 $A$,再删除石头 $C$,最少留下 $1$ 个石头。
- 如果有 $n$ 个石头,其中每个石头都有一个同行或者同列的石头,则我们可以将 $n - 1$ 个石头都删除,最少留下 $1$ 个石头。

通过上面的分析,我们可以利用并查集,将同行、同列的石头都加入到一个集合中。这样「最少可以留下的石头」就是并查集中集合的个数。

Expand Down Expand Up @@ -116,5 +116,5 @@ class Solution:

### 思路 1:复杂度分析

- **时间复杂度**:$O(n \times \alpha(n))$。其中 $n$ 是石子个数。$\alpha$ 是反 `Ackerman` 函数。
- **时间复杂度**:$O(n \times \alpha(n))$。其中 $n$ 是石子个数。$\alpha$ 是反 Ackerman 函数。
- **空间复杂度**:$O(n)$。
50 changes: 43 additions & 7 deletions Solutions/1631. 最小体力消耗路径.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,58 @@

## 题目大意

给定一个 `rows * cols` 大小的二维数组 `heights`,其中 `heights[i][j]` 表示为位置 `(i, j)` 的高度。
**描述**给定一个 $rows \times cols$ 大小的二维数组 $heights$,其中 $heights[i][j]$ 表示为位置 $(i, j)$ 的高度。

现在要从左上角 `(0, 0)` 位置出发,经过方格的一些点,到达右下角 `(n - 1, n - 1)` 位置上。其中所经过路径的花费为「这条路径上所有相邻位置的最大高度差绝对值」。
现在要从左上角 $(0, 0)$ 位置出发,经过方格的一些点,到达右下角 $(n - 1, n - 1)$ 位置上。其中所经过路径的花费为「这条路径上所有相邻位置的最大高度差绝对值」。

现在要求:计算从 `(0, 0)` 位置到 `(n - 1, n - 1)` 的最优路径的花费。
**要求**:计算从 $(0, 0)$ 位置到 $(n - 1, n - 1)$ 的最优路径的花费。

最优路径指的路径上「所有相邻位置最大高度差绝对值」最小的那条路径。
**说明**

- **最优路径**:路径上「所有相邻位置最大高度差绝对值」最小的那条路径。
- $rows == heights.length$。
- $columns == heights[i].length$。
- $1 \le rows, columns \le 100$。
- $1 \le heights[i][j] \le 10^6$。

**示例**

- 示例 1:

![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/10/25/ex1.png)

```python
输入:heights = [[1,2,2],[3,8,2],[5,3,5]]
输出:2
解释:路径 [1,3,5,3,5] 连续格子的差值绝对值最大为 2
这条路径比路径 [1,2,2,2,5] 更优,因为另一条路径差值最大值为 3
```

- 示例 2:

![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/10/25/ex2.png)

```python
输入:heights = [[1,2,3],[3,8,4],[5,3,5]]
输出:1
解释:路径 [1,2,3,4,5] 的相邻格子差值绝对值最大为 1 ,比路径 [1,3,5,3,5] 更优。
```

## 解题思路

### 思路 1:并查集

将整个网络抽象为一个无向图,每个点与相邻的点(上下左右)之间都存在一条无向边,边的权重为两个点之间的高度差绝对值。

我们要找到左上角到右下角的最优路径,可以遍历所有的点,将所有的边存储到数组中,每条边的存储格式为 `[x, y, h]`,意思是编号 `x` 的点和编号为 `y` 的点之间的权重为 `h`
我们要找到左上角到右下角的最优路径,可以遍历所有的点,将所有的边存储到数组中,每条边的存储格式为 $[x, y, h]$,意思是编号 $x$ 的点和编号为 $y$ 的点之间的权重为 $h$

然后按照权重从小到大的顺序,对所有边进行排序。

再按照权重大小遍历所有边,将其依次加入并查集中。并且每次都需要判断 `(0, 0)` 点和 `(n - 1, n - 1)` 点是否连通。
再按照权重大小遍历所有边,将其依次加入并查集中。并且每次都需要判断 $(0, 0)$ 点和 $(n - 1, n - 1)$ 点是否连通。

如果连通,则该边的权重即为答案。

## 代码
### 思路 1:代码

```python
class UnionFind:
Expand Down Expand Up @@ -83,3 +114,8 @@ class Solution:
return 0
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(m \times n \times \alpha(m \times n))$,其中 $\alpha$ 是反 Ackerman 函数。
- **空间复杂度**:$O(m \times n)$。

0 comments on commit f1dfdd6

Please sign in to comment.