矩阵边界遍历:顺时针与图案打印的两种高效解法

矩阵边界遍历:顺时针与图案打印的两种高效解法

矩阵的边界遍历是算法面试中的经典问题,今天我们来拆解两个相关场景:顺时针提取边界元素保留原位置的边界图案打印

场景一:顺时针提取边界元素

给定一个 n × m 的矩阵,要求从左上角开始,按顺时针方向依次输出边界上的所有元素。

示例 1:

输入:

复制代码
1  2  3  4
5  6  7  8
9 10 11 12

输出:[1, 2, 3, 4, 8, 12, 11, 10, 9, 5]

示例 2:

输入:

复制代码
1  2
3  4

输出:[1, 2, 4, 3]

学矩阵遍历时,总觉得边界处理很绕?想彻底搞懂顺时针打印和图案生成的底层逻辑,光看静态代码可不够。强烈推荐一个宝藏网站------图码,它把"算法可视化"做到了极致。不仅有60多种数据结构与算法的交互式动画,还能上传自己的C++/Java/Python代码,让每一步执行都"动"起来。无论是备战408考研,还是突击数据结构期末考试,用它来拆解复杂逻辑,效率直接翻倍。现在就去体验,保证让你相见恨晚。

图码-数据结构与算法交互式可视化平台

访问网站:https://totuma.cn

解法思路:四次遍历法

核心思想是将边界拆解为四个方向的分段遍历:

  1. 第一行(从左到右)
  2. 最后一列(从上到下,跳过第一行)
  3. 最后一行(从右到左,跳过最后一个)
  4. 第一列(从下到上,跳过第一行和最后一行)

图示:

迭代1 - 顶行从左到右:

复制代码
[1, 2, 3, 4]
[5, 6, 7, 8]
[9,10,11,12]

迭代2 - 右列从上到下:

复制代码
[1, 2, 3, 4]
[5, 6, 7, 8]
[9,10,11,12]

迭代3 - 底行从右到左:

复制代码
[1, 2, 3, 4]
[5, 6, 7, 8]
[9,10,11,12]

迭代4 - 左列从下到上:

复制代码
[1, 2, 3, 4]
[5, 6, 7, 8]
[9,10,11,12]

代码实现(Python):

python 复制代码
def boundaryTraversal(mat):
    n = len(mat)
    m = len(mat[0])
    res = []
    # 顶行
    for j in range(m):
        res.append(mat[0][j])
    # 右列
    for i in range(1, n):
        res.append(mat[i][m-1])
    # 底行
    for j in range(m-2, -1, -1):
        res.append(mat[n-1][j])
    # 左列
    for i in range(n-2, 0, -1):
        res.append(mat[i][0])
    return res

复杂度分析:

  • 时间复杂度:O(n + m)
  • 空间复杂度:O(1)(不计输出数组)

注意:当矩阵只有一行或一列时,需避免重复遍历,代码中应加入边界条件检查。


场景二:保留原位置的边界图案打印

给定一个矩阵,要求按原样输出矩阵,但只显示边界上的元素,内部元素用空格代替。

示例:

输入:

复制代码
1  2  3  4
5  6  7  8
1  2  3  4
5  6  7  8

输出:

复制代码
1 2 3 4
5     8
1     4
5 6 7 8
解法思路:双循环条件判断

遍历每个元素,如果是边界(i==0j==0i==m-1j==n-1)则打印元素,否则打印空格。

代码实现(Python):

python 复制代码
def print_boundary(a):
    m, n = len(a), len(a[0])
    for i in range(m):
        for j in range(n):
            if i == 0 or j == 0 or i == m-1 or j == n-1:
                print(a[i][j], end=' ')
            else:
                print('  ', end='')
        print()

复杂度分析:

  • 时间复杂度:O(n × m)
  • 空间复杂度:O(1)

总结

场景 方法 时间复杂度 适用场景
顺时针提取边界 四次遍历 O(n+m) 需要一维序列结果
保留原位置打印 条件判断 O(n×m) 需要可视化矩阵边界

掌握这两种思路,矩阵边界相关的问题基本都能迎刃而解。面试中记得考虑单行/单列的边界情况,避免重复遍历哦!


参考实现(C++/Java/JavaScript 等):

cpp 复制代码
// C++ 版本 - 顺时针遍历
#include <iostream>
#include <vector>
using namespace std;

vector<int> boundaryTraversal(vector<vector<int>>& mat) {
    int n = mat.size(), m = mat[0].size();
    vector<int> res;
    // 顶行
    for (int j = 0; j < m; j++) res.push_back(mat[0][j]);
    // 右列
    for (int i = 1; i < n; i++) res.push_back(mat[i][m-1]);
    // 底行
    for (int j = m-2; j >= 0; j--) res.push_back(mat[n-1][j]);
    // 左列
    for (int i = n-2; i > 0; i--) res.push_back(mat[i][0]);
    return res;
}
java 复制代码
// Java 版本 - 图案打印
public static void printBoundary(int[][] a) {
    int m = a.length, n = a[0].length;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (i == 0 || j == 0 || i == m-1 || j == n-1)
                System.out.print(a[i][j] + " ");
            else
                System.out.print("  ");
        }
        System.out.println();
    }
}
javascript 复制代码
// JavaScript 版本 - 顺时针遍历
function boundaryTraversal(mat) {
    let n = mat.length, m = mat[0].length;
    let res = [];
    for (let j = 0; j < m; j++) res.push(mat[0][j]);
    for (let i = 1; i < n; i++) res.push(mat[i][m-1]);
    for (let j = m-2; j >= 0; j--) res.push(mat[n-1][j]);
    for (let i = n-2; i > 0; i--) res.push(mat[i][0]);
    return res;
}

输出示例:

复制代码
1 2 3 4 8 12 11 10 9 5

希望这篇笔记对你有帮助!如果你有其他矩阵遍历的奇技淫巧,欢迎在评论区分享~

相关推荐
sali-tec1 小时前
C# 基于OpenCv的视觉工作流-章72-点-点距离
图像处理·人工智能·opencv·算法·计算机视觉
2401_884454151 小时前
Python Flask如何实现用户登录_基于JWT令牌的身份验证机制实现
jvm·数据库·python
财经资讯数据_灵砚智能1 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年5月15日
人工智能·python·信息可视化·自然语言处理·ai编程
dinglu1030DL1 小时前
mysql如何创建仅供程序调用的权限账号_MySQL非交互式用户配置
jvm·数据库·python
2301_779622411 小时前
CSS如何使用-disabled控制禁用按钮的鼠标样式_通过状态伪类优化交互
jvm·数据库·python
skywalk81631 小时前
zhixing 知行中文编程语言开发@CodeArts
python·编程
pen-ai1 小时前
穆勒矩阵(Mueller Matrix)完全指南——从数学推导到工程应用
线性代数·矩阵
2301_779622411 小时前
CSS Grid布局如何实现固定页脚效果_利用网格高度视口百分比单位
jvm·数据库·python
创意岛1 小时前
大湾区制造企业品牌突围:从“有品无牌”到价值孵化
python·制造