From f1dfdd69c453e4e2cea8ec0e304945a83f1a6bad Mon Sep 17 00:00:00 2001 From: ITCharge Date: Fri, 10 Nov 2023 10:04:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=A2=98=E8=A7=A3=E5=88=97?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...40\344\270\255\346\270\270\346\263\263.md" | 54 ++++++++++-- .... \346\211\223\347\240\226\345\235\227.md" | 86 ++++++++++++++++--- ...14\345\210\227\347\237\263\345\244\264.md" | 12 +-- ...10\350\200\227\350\267\257\345\276\204.md" | 50 +++++++++-- 4 files changed, 168 insertions(+), 34 deletions(-) diff --git "a/Solutions/0778. \346\260\264\344\275\215\344\270\212\345\215\207\347\232\204\346\263\263\346\261\240\344\270\255\346\270\270\346\263\263.md" "b/Solutions/0778. \346\260\264\344\275\215\344\270\212\345\215\207\347\232\204\346\263\263\346\261\240\344\270\255\346\270\270\346\263\263.md" index 49b242d8..6c108154 100644 --- "a/Solutions/0778. \346\260\264\344\275\215\344\270\212\345\215\207\347\232\204\346\263\263\346\261\240\344\270\255\346\270\270\346\263\263.md" +++ "b/Solutions/0778. \346\260\264\344\275\215\344\270\212\345\215\207\347\232\204\346\263\263\346\261\240\344\270\255\346\270\270\346\263\263.md" @@ -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: @@ -83,3 +118,8 @@ class Solution: return 0 ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(m \times n \times \alpha(m \times n))$,其中 $\alpha$ 是反 Ackerman 函数。 +- **空间复杂度**:$O(m \times n)$。 + diff --git "a/Solutions/0803. \346\211\223\347\240\226\345\235\227.md" "b/Solutions/0803. \346\211\223\347\240\226\345\235\227.md" index 7435ac99..a438c2d1 100644 --- "a/Solutions/0803. \346\211\223\347\240\226\345\235\227.md" +++ "b/Solutions/0803. \346\211\223\347\240\226\345\235\227.md" @@ -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: @@ -119,3 +172,8 @@ class Solution: return res ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(m \times n \times \alpha(m \times n))$,其中 $\alpha$ 是反 Ackerman 函数。 +- **空间复杂度**:$O(m \times n)$。 + diff --git "a/Solutions/0947. \347\247\273\351\231\244\346\234\200\345\244\232\347\232\204\345\220\214\350\241\214\346\210\226\345\220\214\345\210\227\347\237\263\345\244\264.md" "b/Solutions/0947. \347\247\273\351\231\244\346\234\200\345\244\232\347\232\204\345\220\214\350\241\214\346\210\226\345\220\214\345\210\227\347\237\263\345\244\264.md" index c101339d..c4d82edf 100644 --- "a/Solutions/0947. \347\247\273\351\231\244\346\234\200\345\244\232\347\232\204\345\220\214\350\241\214\346\210\226\345\220\214\345\210\227\347\237\263\345\244\264.md" +++ "b/Solutions/0947. \347\247\273\351\231\244\346\234\200\345\244\232\347\232\204\345\220\214\350\241\214\346\210\226\345\220\214\345\210\227\347\237\263\345\244\264.md" @@ -5,9 +5,9 @@ ## 题目大意 -**描述**:二维平面中有 `n` 块石头,每块石头都在整数坐标点上,且每个坐标点上最多只能有一块石头。如果一块石头的同行或者同列上有其他石头存在,那么就可以移除这块石头。 +**描述**:二维平面中有 $n$ 块石头,每块石头都在整数坐标点上,且每个坐标点上最多只能有一块石头。如果一块石头的同行或者同列上有其他石头存在,那么就可以移除这块石头。 -给你一个长度为 `n` 的数组 `stones` ,其中 `stones[i] = [xi, yi]` 表示第 `i` 块石头的位置。 +给你一个长度为 $n$ 的数组 $stones$ ,其中 $stones[i] = [xi, yi]$ 表示第 $i$ 块石头的位置。 **要求**:返回可以移除的石子的最大数量。 @@ -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$ 个石头。 通过上面的分析,我们可以利用并查集,将同行、同列的石头都加入到一个集合中。这样「最少可以留下的石头」就是并查集中集合的个数。 @@ -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)$。 \ No newline at end of file diff --git "a/Solutions/1631. \346\234\200\345\260\217\344\275\223\345\212\233\346\266\210\350\200\227\350\267\257\345\276\204.md" "b/Solutions/1631. \346\234\200\345\260\217\344\275\223\345\212\233\346\266\210\350\200\227\350\267\257\345\276\204.md" index 3fb02a0b..ce8b4d54 100644 --- "a/Solutions/1631. \346\234\200\345\260\217\344\275\223\345\212\233\346\266\210\350\200\227\350\267\257\345\276\204.md" +++ "b/Solutions/1631. \346\234\200\345\260\217\344\275\223\345\212\233\346\266\210\350\200\227\350\267\257\345\276\204.md" @@ -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: @@ -83,3 +114,8 @@ class Solution: return 0 ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(m \times n \times \alpha(m \times n))$,其中 $\alpha$ 是反 Ackerman 函数。 +- **空间复杂度**:$O(m \times n)$。 +