【数组】LeetCode 59.螺旋矩阵Ⅱ

62 阅读5分钟

难度:中等

描述:

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。  

示例 1:

输入: n = 3
输出: [[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入: n = 1
输出: [[1]]

 

提示:

  • 1 <= n <= 20

思路

这道题目可以说在面试中出现频率较高的题目,本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。

要如何画出这个螺旋排列的正方形矩阵呢?

相信很多同学刚开始做这种题目的时候,上来就是一波判断猛如虎。

结果运行的时候各种问题,然后开始各种修修补补,最后发现改了这里那里有问题,改了那里这里又跑不起来了。

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去。

可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是一进循环深似海,从此offer是路人

这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。

那么我按照左闭右开的原则,来画一圈,大家看一下:

这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。

这也是坚持了每条边左闭右开的原则。

一些同学做这道题目之所以一直写不好,代码越写越乱。

就是因为在画每一条边的时候,一会左开右闭,一会左闭右闭,一会又来左闭右开,岂能不乱。

C语言版代码:

/**
 * @brief 59.螺旋矩阵 II
 *
 * @param n	矩阵的长和宽
 * @param returnSize	返回生成的矩阵有多少行
 * @param returnColumnSizes	返回矩阵每一行有多少列
 *
 * @return 螺旋矩阵
 **/
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes) {
    *returnSize = n;
    *returnColumnSizes = (int*)malloc(sizeof(int) * n);
    int** matrix = (int**)malloc(sizeof(int*) * n); // 创建二维数组
    for (int i = 0; i < n; i++) {
        matrix[i] = (int*)malloc(sizeof(int) * n);
        (*returnColumnSizes)[i] = n;
    }
    // 初始化四个边界变量,定义当前要填充的"圈"的边界
    int t = 0;         // top - 上边界
    int b = n - 1;     // bottom - 下边界
    int l = 0;         // left - 左边界
    int r = n - 1;     // right - 右边界
    int k = 1;         // 要填充的数字,从1开始
    while (k <= n * n) {
        for (int i = l; i <= r; ++i, ++k) matrix[t][i] = k;		// 填充上边(从左到右)
        ++t;	// 填充完成后,上边界t下移一行(++t)

        for (int i = t; i <= b; ++i, ++k) matrix[i][r] = k;		// 填充右边(从上到下)
        --r;	// 填充完成后,右边界r左移一列(--r)

        for (int i = r; i >= l; --i, ++k) matrix[b][i] = k;		// 填充下边(从右到左)
        --b;	// 填充完成后,下边界b上移一行(--b)

        for (int i = b; i >= t; --i, ++k) matrix[i][l] = k;		// 填充左边(从下到上)
        ++l;	// 填充完成后,左边界l右移一列(++l)
    }
    return matrix;
}

完整示例

C语言版:

#include <stdio.h>
#include <stdlib.h>


/**
 * @brief 59.螺旋矩阵 II
 *
 * @param n	矩阵的长和宽
 * @param returnSize	返回生成的矩阵有多少行
 * @param returnColumnSizes	返回矩阵每一行有多少列
 *
 * @return 螺旋矩阵
 **/
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes) {
    *returnSize = n;
    *returnColumnSizes = (int*)malloc(sizeof(int) * n);
    int** matrix = (int**)malloc(sizeof(int*) * n); // 创建二维数组
    for (int i = 0; i < n; i++) {
            matrix[i] = (int*)malloc(sizeof(int) * n);
            (*returnColumnSizes)[i] = n;
    }
    // 初始化四个边界变量,定义当前要填充的"圈"的边界
    int t = 0;         // top - 上边界
    int b = n - 1;     // bottom - 下边界
    int l = 0;         // left - 左边界
    int r = n - 1;     // right - 右边界
    int k = 1;         // 要填充的数字,从1开始
    while (k <= n * n) {
        for (int i = l; i <= r; ++i, ++k) matrix[t][i] = k;		// 填充上边(从左到右)
        ++t;	// 填充完成后,上边界t下移一行(++t)

        for (int i = t; i <= b; ++i, ++k) matrix[i][r] = k;		// 填充右边(从上到下)
        --r;	// 填充完成后,右边界r左移一列(--r)

        for (int i = r; i >= l; --i, ++k) matrix[b][i] = k;		// 填充下边(从右到左)
        --b;	// 填充完成后,下边界b上移一行(--b)

        for (int i = b; i >= t; --i, ++k) matrix[i][l] = k;		// 填充左边(从下到上)
        ++l;	// 填充完成后,左边界l右移一列(++l)
    }
    return matrix;
}

int main() {
    int n = 5; // 定义矩阵大小
    int returnSize; // 用于接收矩阵的行数
    int* returnColumnSizes; // 用于接收每行列数的数组指针
    int** resultMatrix; // 用于接收生成的二维矩阵

    // 调用函数,注意传递的是地址
    resultMatrix = generateMatrix(n, &returnSize, &returnColumnSizes);

    // 打印生成的螺旋矩阵
    printf("生成的 %dx%d 螺旋矩阵为:\n", n, n);
    for (int i = 0; i < returnSize; i++) { // 遍历每一行
        for (int j = 0; j < returnColumnSizes[i]; j++) { // 遍历当前行的每一列
            printf("%02d ", resultMatrix[i][j]);
        }
        printf("\n");
    }

    // !!!重要:释放内存 !!!
    for (int i = 0; i < returnSize; i++) {
        free(resultMatrix[i]); // 先释放每一行(一维数组)
    }
    free(resultMatrix); // 再释放存储行指针的数组
    free(returnColumnSizes); // 最后释放存储列宽的数组

    return 0;
}