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

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

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

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

给定一个 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==0、j==0、i==m-1、j==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

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

相关推荐
东莞市云毅网络有限公司3 小时前
AI 引用句逐条回指原文:让回答可回溯的校验实现
python·数据清洗·rag·企业知识库·文档解析
数字融合5 小时前
透明化视频三维矿山井下照明重建技术
人工智能·python·数码相机
yi0115 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
Marst Code7 小时前
上位机开发日记 · 第 2 篇 · 架构先行:六层分层与边界
python
李日华大战鸡红7 小时前
FOC状态空间方程模型推导(学习记录)
python·学习·线性代数
灯澜忆梦8 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
禾小西8 小时前
Redis 数据结构:快速的 Redis 有哪些慢操作?
数据结构·数据库·redis
小蒋观天下8 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J8 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛8 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法