update content

This commit is contained in:
labuladong
2024-07-18 02:43:33 +08:00
parent 02891deeb9
commit ea12e107fe
3 changed files with 4 additions and 235 deletions

View File

@ -266,8 +266,8 @@ PDF 共两本一本《labuladong 的算法秘籍》类似教材,帮你系
* [手把手刷图算法](https://labuladong.online/algo/)
* [图论基础及遍历算法](https://labuladong.online/algo/data-structure/graph-traverse/)
* [众里寻他千百度:名流问题](https://labuladong.online/algo/frequency-interview/find-celebrity/)
* [环检测及拓扑排序算法](https://labuladong.online/algo/data-structure/topological-sort/)
* [众里寻他千百度:名流问题](https://labuladong.online/algo/frequency-interview/find-celebrity/)
* [二分图判定算法](https://labuladong.online/algo/data-structure/bipartite-graph/)
* [并查集Union-Find算法](https://labuladong.online/algo/data-structure/union-find/)
* [Kruskal 最小生成树算法](https://labuladong.online/algo/data-structure/kruskal/)

View File

@ -325,6 +325,7 @@ void levelTraverse(TreeNode root) {
| [286. Walls and Gates](https://leetcode.com/problems/walls-and-gates/?show=1)🔒 | [286. 墙与门](https://leetcode.cn/problems/walls-and-gates/?show=1)🔒 |
| [310. Minimum Height Trees](https://leetcode.com/problems/minimum-height-trees/?show=1) | [310. 最小高度树](https://leetcode.cn/problems/minimum-height-trees/?show=1) |
| [329. Longest Increasing Path in a Matrix](https://leetcode.com/problems/longest-increasing-path-in-a-matrix/?show=1) | [329. 矩阵中的最长递增路径](https://leetcode.cn/problems/longest-increasing-path-in-a-matrix/?show=1) |
| [505. The Maze II](https://leetcode.com/problems/the-maze-ii/?show=1)🔒 | [505. 迷宫 II](https://leetcode.cn/problems/the-maze-ii/?show=1)🔒 |
| [542. 01 Matrix](https://leetcode.com/problems/01-matrix/?show=1) | [542. 01 矩阵](https://leetcode.cn/problems/01-matrix/?show=1) |
</details>

View File

@ -100,238 +100,6 @@ s = "labuladong world hello"
**旨在说明,有时候咱们拍脑袋的常规思维,在计算机看来可能并不是最优雅的;但是计算机觉得最优雅的思维,对咱们来说却不那么直观**。也许这就是算法的魅力所在吧。
回到之前说的顺时针旋转二维矩阵的问题,常规的思路就是去寻找原始坐标和旋转后坐标的映射规律,但我们是否可以让思维跳跃跳跃,尝试把矩阵进行反转、镜像对称等操作,可能会出现新的突破口。
**我们可以先将 `n x n` 矩阵 `matrix` 按照左上到右下的对角线进行镜像对称**
![](https://labuladong.online/algo/images/花式遍历/2.jpeg)
**然后再对矩阵的每一行进行反转**
![](https://labuladong.online/algo/images/花式遍历/3.jpeg)
**发现结果就是 `matrix` 顺时针旋转 90 度的结果**
![](https://labuladong.online/algo/images/花式遍历/4.jpeg)
将上述思路翻译成代码,即可解决本题:
<!-- muliti_language -->
```java
// 将二维矩阵原地顺时针旋转 90 度
public void rotate(int[][] matrix) {
int n = matrix.length;
// 先沿对角线镜像对称二维矩阵
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// swap(matrix[i][j], matrix[j][i]);
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 然后反转二维矩阵的每一行
for (int[] row : matrix) {
reverse(row);
}
}
// 反转一维数组
void reverse(int[] arr) {
int i = 0, j = arr.length - 1;
while (j > i) {
// swap(arr[i], arr[j]);
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
}
```
<visual slug='rotate-image'/>
肯定有读者会问,如果没有做过这道题,怎么可能想到这种思路呢?
是的,没做过这类题目,确实不好想到这种思路,但你这不是做过了么?所谓会者不难难者不会,你这辈子估计都忘不掉了。
**既然说道这里,我们可以发散一下,如何将矩阵逆时针旋转 90 度呢**
思路是类似的,只要通过另一条对角线镜像对称矩阵,然后再反转每一行,就得到了逆时针旋转矩阵的结果:
![](https://labuladong.online/algo/images/花式遍历/5.jpeg)
翻译成代码如下:
<!-- muliti_language -->
```java
// 将二维矩阵原地逆时针旋转 90 度
void rotate2(int[][] matrix) {
int n = matrix.length;
// 沿左下到右上的对角线镜像对称二维矩阵
for (int i = 0; i < n; i++) {
for (int j = 0; j < n - i; j++) {
// swap(matrix[i][j], matrix[n-j-1][n-i-1])
int temp = matrix[i][j];
matrix[i][j] = matrix[n - j - 1][n - i - 1];
matrix[n - j - 1][n - i - 1] = temp;
}
}
// 然后反转二维矩阵的每一行
for (int[] row : matrix) {
reverse(row);
}
}
void reverse(int[] arr) { /* 见上文 */}
```
至此,旋转矩阵的问题就解决了。
### 矩阵的螺旋遍历
我的公众号动态规划系列文章经常需要遍历二维 `dp` 数组,但难点在于状态转移方程而不是数组的遍历,顶多就是倒序遍历。
但接下来我们讲一下力扣第 54 题「螺旋矩阵」,看一看二维矩阵可以如何花式遍历:
<Problem slug="spiral-matrix" />
函数签名如下:
<!-- muliti_language -->
```java
List<Integer> spiralOrder(int[][] matrix)
```
**解题的核心思路是按照右、下、左、上的顺序遍历数组,并使用四个变量圈定未遍历元素的边界**
![](https://labuladong.online/algo/images/花式遍历/6.png)
随着螺旋遍历,相应的边界会收缩,直到螺旋遍历完整个数组:
![](https://labuladong.online/algo/images/花式遍历/7.png)
只要有了这个思路,翻译出代码就很容易了:
<!-- muliti_language -->
```java
List<Integer> spiralOrder(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
int upper_bound = 0, lower_bound = m - 1;
int left_bound = 0, right_bound = n - 1;
List<Integer> res = new LinkedList<>();
// res.size() == m * n 则遍历完整个数组
while (res.size() < m * n) {
if (upper_bound <= lower_bound) {
// 在顶部从左向右遍历
for (int j = left_bound; j <= right_bound; j++) {
res.add(matrix[upper_bound][j]);
}
// 上边界下移
upper_bound++;
}
if (left_bound <= right_bound) {
// 在右侧从上向下遍历
for (int i = upper_bound; i <= lower_bound; i++) {
res.add(matrix[i][right_bound]);
}
// 右边界左移
right_bound--;
}
if (upper_bound <= lower_bound) {
// 在底部从右向左遍历
for (int j = right_bound; j >= left_bound; j--) {
res.add(matrix[lower_bound][j]);
}
// 下边界上移
lower_bound--;
}
if (left_bound <= right_bound) {
// 在左侧从下向上遍历
for (int i = lower_bound; i >= upper_bound; i--) {
res.add(matrix[i][left_bound]);
}
// 左边界右移
left_bound++;
}
}
return res;
}
```
力扣第 59 题「螺旋矩阵 II」也是类似的题目只不过是反过来让你按照螺旋的顺序生成矩阵
<Problem slug="spiral-matrix-ii" />
函数签名如下:
<!-- muliti_language -->
```java
int[][] generateMatrix(int n)
```
有了上面的铺垫,稍微改一下代码即可完成这道题:
<!-- muliti_language -->
```java
int[][] generateMatrix(int n) {
int[][] matrix = new int[n][n];
int upper_bound = 0, lower_bound = n - 1;
int left_bound = 0, right_bound = n - 1;
// 需要填入矩阵的数字
int num = 1;
while (num <= n * n) {
if (upper_bound <= lower_bound) {
// 在顶部从左向右遍历
for (int j = left_bound; j <= right_bound; j++) {
matrix[upper_bound][j] = num++;
}
// 上边界下移
upper_bound++;
}
if (left_bound <= right_bound) {
// 在右侧从上向下遍历
for (int i = upper_bound; i <= lower_bound; i++) {
matrix[i][right_bound] = num++;
}
// 右边界左移
right_bound--;
}
if (upper_bound <= lower_bound) {
// 在底部从右向左遍历
for (int j = right_bound; j >= left_bound; j--) {
matrix[lower_bound][j] = num++;
}
// 下边界上移
lower_bound--;
}
if (left_bound <= right_bound) {
// 在左侧从下向上遍历
for (int i = lower_bound; i >= upper_bound; i--) {
matrix[i][left_bound] = num++;
}
// 左边界右移
left_bound++;
}
}
return matrix;
}
```
至此,两道螺旋矩阵的题目也解决了。
以上就是遍历二维数组的一些技巧,其他数组技巧可参见之前的文章 [前缀和数组](https://labuladong.online/algo/data-structure/prefix-sum/)[差分数组](https://labuladong.online/algo/data-structure/diff-array/)[数组双指针算法集合](https://labuladong.online/algo/essential-technique/array-two-pointers-summary/),链表相关技巧可参见 [单链表六大算法技巧汇总](https://labuladong.online/algo/essential-technique/linked-list-skills-summary/)。
<hr>
@ -365,6 +133,6 @@ int[][] generateMatrix(int n) {
**_____________**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.online/algo/practice-in-action/2d-array-traversal-summary/) 查看
![](https://labuladong.online/algo/images/souyisou2.png)
![](https://labuladong.online/algo/images/qrcode.jpg)