From ea12e107fe33bb99ff71705da5360475d07271a2 Mon Sep 17 00:00:00 2001 From: labuladong Date: Thu, 18 Jul 2024 02:43:33 +0800 Subject: [PATCH] update content --- README.md | 2 +- 数据结构系列/dijkstra算法.md | 1 + 算法思维系列/花式遍历.md | 236 +---------------------------------- 3 files changed, 4 insertions(+), 235 deletions(-) diff --git a/README.md b/README.md index e82f711..88f1417 100644 --- a/README.md +++ b/README.md @@ -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/) diff --git a/数据结构系列/dijkstra算法.md b/数据结构系列/dijkstra算法.md index 24253d6..4733650 100644 --- a/数据结构系列/dijkstra算法.md +++ b/数据结构系列/dijkstra算法.md @@ -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) | diff --git a/算法思维系列/花式遍历.md b/算法思维系列/花式遍历.md index 22c1918..7d6ab86 100644 --- a/算法思维系列/花式遍历.md +++ b/算法思维系列/花式遍历.md @@ -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) - -将上述思路翻译成代码,即可解决本题: - - -```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--; - } -} -``` - - - -肯定有读者会问,如果没有做过这道题,怎么可能想到这种思路呢? - -是的,没做过这类题目,确实不好想到这种思路,但你这不是做过了么?所谓会者不难难者不会,你这辈子估计都忘不掉了。 - -**既然说道这里,我们可以发散一下,如何将矩阵逆时针旋转 90 度呢**? - -思路是类似的,只要通过另一条对角线镜像对称矩阵,然后再反转每一行,就得到了逆时针旋转矩阵的结果: - -![](https://labuladong.online/algo/images/花式遍历/5.jpeg) - -翻译成代码如下: - - -```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 题「螺旋矩阵」,看一看二维矩阵可以如何花式遍历: - - - -函数签名如下: - - -```java -List spiralOrder(int[][] matrix) -``` - -**解题的核心思路是按照右、下、左、上的顺序遍历数组,并使用四个变量圈定未遍历元素的边界**: - -![](https://labuladong.online/algo/images/花式遍历/6.png) - -随着螺旋遍历,相应的边界会收缩,直到螺旋遍历完整个数组: - -![](https://labuladong.online/algo/images/花式遍历/7.png) - -只要有了这个思路,翻译出代码就很容易了: - - -```java -List 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 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」也是类似的题目,只不过是反过来,让你按照螺旋的顺序生成矩阵: - - - -函数签名如下: - - -```java -int[][] generateMatrix(int n) -``` - -有了上面的铺垫,稍微改一下代码即可完成这道题: - - -```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/)。 - - -
@@ -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) \ No newline at end of file +![](https://labuladong.online/algo/images/qrcode.jpg) \ No newline at end of file