54. 螺旋矩阵(C++)

题目

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
在这里插入图片描述

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
在这里插入图片描述

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

提示:

m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100

题解

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> result;
        if (matrix.empty() || matrix[0].empty()) return result;

        int rows = matrix.size();
        int cols = matrix[0].size();
        int left = 0, right = cols - 1, top = 0, bottom = rows - 1;

        while (left <= right && top <= bottom) {
            // 从左到右遍历上边界
            for (int col = left; col <= right; col++) {
                result.push_back(matrix[top][col]);
            }
            top++;

            // 从上到下遍历右边界
            for (int row = top; row <= bottom; row++) {
                result.push_back(matrix[row][right]);
            }
            right--;

            // 若上下边界未重合,从右到左遍历下边界
            if (top <= bottom) {
                for (int col = right; col >= left; col--) {
                    result.push_back(matrix[bottom][col]);
                }
                bottom--;
            }

            // 若左右边界未重合,从下到上遍历左边界
            if (left <= right) {
                for (int row = bottom; row >= top; row--) {
                    result.push_back(matrix[row][left]);
                }
                left++;
            }
        }

        return result;
    }
};

算法原理

整体目标

该算法的目标是按照顺时针螺旋顺序遍历一个二维矩阵,并将遍历到的元素依次存储在一个一维向量中返回。为了实现这个目标,我们采用了一种边界控制的方法,通过定义矩阵的四个边界(左、右、上、下),并按照顺时针方向依次遍历这些边界上的元素,同时不断收缩边界,直到遍历完整个矩阵。

1. 初始化边界

在开始遍历之前,我们需要明确矩阵的边界信息。假设矩阵有 mn 列,我们定义四个变量来表示矩阵的边界:

  • left:矩阵左边界的列索引,初始值为 0。
  • right:矩阵右边界的列索引,初始值为 n - 1
  • top:矩阵上边界的行索引,初始值为 0。
  • bottom:矩阵下边界的行索引,初始值为 m - 1

这些边界变量将帮助我们确定每次遍历的范围。

2. 循环遍历矩阵

使用一个 while 循环来控制遍历过程,循环条件为 left <= righttop <= bottom。只要满足这个条件,就说明矩阵中还有未遍历的元素,继续进行遍历。

3. 顺时针遍历边界

在每次循环中,按照顺时针方向依次遍历矩阵的四个边界:

(1)从左到右遍历上边界
for (int col = left; col <= right; col++) {
    result.push_back(matrix[top][col]);
}
top++;
  • 原理:从矩阵的左上角开始,沿着当前上边界(第 top 行)从左到右依次访问元素,并将其添加到结果向量 result 中。遍历完上边界后,上边界向下移动一行,即 top 加 1。
(2)从上到下遍历右边界
for (int row = top; row <= bottom; row++) {
    result.push_back(matrix[row][right]);
}
right--;
  • 原理:从当前上边界的下一行(top 行)开始,沿着右边界(第 right 列)从上到下依次访问元素,并将其添加到结果向量中。遍历完右边界后,右边界向左移动一列,即 right 减 1。
(3)从右到左遍历下边界
if (top <= bottom) {
    for (int col = right; col >= left; col--) {
        result.push_back(matrix[bottom][col]);
    }
    bottom--;
}
  • 原理:在遍历下边界之前,需要先检查 top 是否小于等于 bottom,因为在某些情况下(例如矩阵只有一行),上边界和下边界可能已经重合,此时不需要再遍历下边界。如果满足条件,从当前右边界的左一列(right 列)开始,沿着下边界(第 bottom 行)从右到左依次访问元素,并将其添加到结果向量中。遍历完下边界后,下边界向上移动一行,即 bottom 减 1。
(4)从下到上遍历左边界
if (left <= right) {
    for (int row = bottom; row >= top; row--) {
        result.push_back(matrix[row][left]);
    }
    left++;
}
  • 原理:在遍历左边界之前,需要先检查 left 是否小于等于 right,因为在某些情况下(例如矩阵只有一列),左边界和右边界可能已经重合,此时不需要再遍历左边界。如果满足条件,从当前下边界的上一行(bottom 行)开始,沿着左边界(第 left 列)从下到上依次访问元素,并将其添加到结果向量中。遍历完左边界后,左边界向右移动一列,即 left 加 1。
4. 结束条件

left > righttop > bottom 时,说明矩阵中的所有元素都已经被遍历完,此时退出循环,返回结果向量 result

复杂度分析

  • 时间复杂度:由于我们需要遍历矩阵中的每个元素一次,矩阵共有 m * n 个元素,因此时间复杂度为 O(m∗n)O(m * n)O(mn)
  • 空间复杂度:除了结果向量外,只使用了常数级的额外空间(四个边界变量),因此空间复杂度为 O(1)O(1)O(1)
<think>首先,用户的问题是关于如何在C++中实现螺旋矩阵算法或代码示例。根据系统指令,我需要使用中文回答,结构清晰,逐步解决问题,并保证回答真实可靠。 回顾用户提供的引用: - 引用[1]:讨论了C++实现螺旋矩阵的遍历问题。 - 引用[2]:介绍了螺旋矩阵的生成与实现,包括C++代码示例。 - 引用[3]:展示了一个数字螺旋矩阵C++代码,使用递归方法。 - 引用[4]和[5]:提供了基于循环的C++代码实现螺旋矩阵生成,类似于LeetCode风格。 用户意图是找到C++实现螺旋矩阵的代码示例。所以,我应该提供清晰的算法解释和代码实现。 关键点: - 螺旋矩阵可以是生成一个n x n的矩阵,其中数字从1到n²按顺时针螺旋顺序填充。 - 实现方法包括递归和迭代(循环)两种。 我需要选择一种常见且高效的方法。引用[4]和[5]展示了迭代方法,使用多层循环来模拟螺旋过程。引用[3]使用了递归方法。 迭代方法更直观且高效,所以我将采用迭代方法。 步骤: 1. **理解螺旋矩阵的生成过程**:对于一个n x n矩阵,从左上角开始,按顺时针方向(右、下、左、上)填充数字。 2. **算法设计**: - 初始化一个n x n的矩阵,所有元素为0。 - 定义起始位置(startX, startY)、偏移量(offset)、当前数字(count)。 - 通过循环处理每一层(圈),直到中心。 - 对于每一圈: - 从左到右填充上行。 - 从上到下填充右列。 - 从右到左填充下行。 - 从下到上填充左列。 - 调整起始位置和偏移量。 - 如果n为奇数,填充中心元素。 3. **代码实现**:基于引用[4]或[5],提供一个C++代码示例。 确保LaTeX格式: - 行内数学表达式用$...$,例如矩阵大小$n \times n$。 - 独立公式用$$...$$,但这里可能不需要。 回答结构: - 先简要介绍螺旋矩阵。 - 解释算法步骤。 - 提供C++代码。 - 解释代码关键部分。 - 最后生成相关问题。 相关问题: - 根据系统指令,生成相关问题,如性能分析、优化方法、应用场景等。 完整回答: - 使用中文。 - 清晰结构:引言、算法、代码、解释、相关问题。 - 引用末尾添加标识,如[^1]。 现在,构建回答: 1. **引言**:介绍螺旋矩阵。 2. **算法步骤**: - 步骤1:初始化变量。 - 步骤2:循环处理每一圈。 - 步骤3:填充四个方向。 - 步骤4:处理奇数n的中心。 3. **代码实现**:提供完整的C++代码。 4. **代码解释**:解释关键部分。 5. **相关问题**:列出相关问题。 代码示例基于引用[5],因为它更简洁。</think>### 如何在C++中实现螺旋矩阵的生成 螺旋矩阵是一种特殊的二维矩阵,其中元素按顺时针螺旋顺序从1填充到$n^2$(对于$n \times n$矩阵)。这种结构在算法面试(如LeetCode问题)和数据处理中常见。下面我将逐步解释实现算法,并提供完整的C++代码示例。算法基于迭代方法,时间复杂度为$O(n^2)$,空间复杂度为$O(1)$,高效且易于理解。 #### 算法步骤 螺旋矩阵的生成可以通过模拟顺时针遍历过程实现: 1. **初始化**:创建一个$n \times n$的二维矩阵,所有元素初始化为0。定义起始位置$(startX, startY)$、偏移量`offset`(控制每圈边界)、当前数字`count`(从1开始),以及圈数`loop = n / 2`。 2. **循环处理每一圈**: - **从左到右填充上行**:从$(startX, startY)$开始,向右移动,填充元素直到边界$n - offset$。 - **从上到下填充右列**:从上到下填充右边界列。 - **从右到左填充下行**:从右到左填充下边界行。 - **从下到上填充左列**:从下到上填充左边界列。 - 每完成一圈,起始位置$(startX, startY)$向内移动(即$startX++$, $startY++$),偏移量`offset++`以收缩边界。 3. **处理中心元素**:如果$n$为奇数(即$n \% 2 \neq 0$),矩阵中心位置$(mid, mid)$单独填充,其中$mid = n / 2$。 4. **终止条件**:圈数`loop`减至0时结束。 #### C++代码实现 以下是完整的C++代码,基于迭代方法实现螺旋矩阵生成。代码包含详细注释,便于理解: ```cpp #include <vector> using namespace std; class Solution { public: vector<vector<int>> generateMatrix(int n) { // 初始化n x n矩阵,所有元素为0 vector<vector<int>> res(n, vector<int>(n, 0)); // 关键变量定义 int startX = 0, startY = 0; // 起始位置(左上角) int offset = 1; // 偏移量,控制边界收缩 int count = 1; // 当前填充的数字(从1开始) int loop = n / 2; // 总圈数(整数除法) int mid = n / 2; // 中心位置(用于n为奇数时) // 循环处理每一圈 while (loop--) { int i = startX, j = startY; // 从左到右填充上行(不包含右边界) for (; j < n - offset; j++) { res[i][j] = count++; } // 从上到下填充右列(不包含下边界) for (; i < n - offset; i++) { res[i][j] = count++; } // 从右到左填充下行(不包含左边界) for (; j > startY; j--) { res[i][j] = count++; } // 从下到上填充左列(不包含上边界) for (; i > startX; i--) { res[i][j] = count++; } // 向内移动起始位置并增加偏移量 startX++; startY++; offset++; } // 如果n为奇数,填充中心元素 if (n % 2) { res[mid][mid] = count; } return res; } }; ``` #### 代码解释 - **初始化**:`vector<vector<int>> res(n, vector<int>(n, 0))` 创建一个$n \times n$矩阵。 - **循环逻辑**:`while (loop--)` 处理每一圈,每圈包含四个方向的填充: - 第一个`for`循环填充上行(从左到右),变量`j`控制列索引。 - 第二个`for`循环填充右列(从上到下),变量`i`控制行索引。 - 第三个`for`循环填充下行(从右到左)。 - 第四个`for`循环填充左列(从下到上)。 - **边界控制**:`offset` 确保每圈边界向内收缩,避免重复填充。 - **奇偶处理**:`if (n % 2)` 检查$n$是否为奇数,并在中心位置填充剩余数字。 - **效率**:时间复杂度$O(n^2)$(遍历所有元素),空间复杂度$O(1)$(额外空间仅用于变量)[^5]。 #### 示例输出 对于$n = 3$,输出矩阵为: ``` 1 2 3 8 9 4 7 6 5 ``` 此代码可直接在LeetCode或任何C++编译器运行,生成任意大小的螺旋矩阵
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值