剑指offer 学习笔记 顺时针打印矩阵

面试题29:顺时针打印矩阵。输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

由于是以从外圈到内圈的顺序依次打印的,所以我们可以把矩阵想象成若干个圈。我们可以用循环打印矩阵,每次打印矩阵中的一个圈。

接下来分析循环结束的条件,假设这个矩阵的行数是rows,列数是columns,打印第一圈的左上角坐标是(0,0),第二圈的左上角坐标是(1,1),以此类推。我们注意到,左上角的坐标中行标和列标总是相同的,于是我们可以在矩阵中选取左上角为(start,start)的一圈作为我们分析目标。

对于一个5*5的矩阵,最后一圈只有一个数字,对应坐标为(2,2),我们发现5>2*2。对于6*6的矩阵而言,最后一圈有四个数字,其左上角的坐标仍为(2,2),6>2*2依然成立。于是得出打印一圈的条件是columns>startX*2,rows>startY*2。

接下来考虑如何打印一圈。我们把打印一圈分为四步:第一步,从左到右打印一行;第二步,从上到下打印一列;第三步,从右向左打印一行;第四步,从下到上打印一列。

在打印时,最后一圈有可能退化成只有一行、只有一列甚至只有一个数字。但第一步总是需要打印的,如果只有一行,就不需要第二步了。第二步的前提条件是终止行号大于起始行号。第三步打印的条件是终止行号大于起始行号并且终止列号大于起始列号。第四步打印的条件是终止行号比起始行号最少大2并且终止列号大于起始列号:

#include <iostream>
using namespace std;

void PrintMatrixInCircle(int** numbers, int rows, int columns, int start) {
    int endX = columns - 1 - start;
    int endY = rows - 1 - start;

    // 打印第一步
    for (int i = start; i <= endX; ++i) {
        cout << numbers[start][i];
    }
    // 打印第二步
    for (int i = start + 1; i <= endY; ++i) {
        cout << numbers[i][endX];
    }
    //打印第三步
    if (endY > start) {    // 当行数大于1时才打印第三步
        for (int i = endX - 1; i >= start; --i) {
            cout << numbers[endY][i]; 
        }
    }
    // 打印第四步
    if (endX > start) {    // 当列数大于1时才打印第四步
        for (int i = endY - 1; i > start; --i) {
            cout << numbers[i][start];
        }
    }
}

void PrintMatrixClockwisely(int** numbers, int rows, int columns) {
    if (numbers == nullptr || rows < 1 || columns < 1) {
        return;
    }
    int start = 0;
    while (2 * start < rows && 2 * start < columns) {
        PrintMatrixInCircle(numbers, rows, columns, start);
        ++start;
    }
}

void Test(int columns, int rows)
{
    printf("Test Begin: %d columns, %d rows.\n", columns, rows);

    if (columns < 1 || rows < 1)
        return;

    int** numbers = new int* [rows];
    for (int i = 0; i < rows; ++i)
    {
        numbers[i] = new int[columns];
        for (int j = 0; j < columns; ++j)
        {
            numbers[i][j] = i * columns + j + 1;
        }
    }

    PrintMatrixClockwisely(numbers, rows, columns);
    printf("\n");

    for (int i = 0; i < rows; ++i)
        delete[](int*)numbers[i];

    delete[] numbers;
}

int main() {
    Test(3, 4);    // 分别输入列、行
}
posted @   epiphanyy  阅读(5)  评论(0编辑  收藏  举报  
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
历史上的今天:
2019-03-03 JAVA类继承
2019-03-03 JAVA构造器
点击右上角即可分享
微信分享提示