TypeScript顺时针打印矩阵实现实例详解

目录
  • 前言
  • 梳理思路
  • 实现代码
  • 示例代码

前言

有一个矩阵,如何按照从外向里以顺时针的顺序依次打印出每一个元素?本文将跟大家分享下这个算法,欢迎各位感兴趣的开发者阅读本文。

梳理思路

当我们遇到一个复杂的问题时,可以通过举例将它画出来,这样就可以更直观的发现规律。那么我们就先构造一个矩阵出来,如下所示:

const matrix = [
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12],
  [13, 14, 15, 16]
];

顺时针访问一个矩阵,那么它的访问过程就如下图所示:

观察上图后,我们可以很明显的知道可以通过一个循环来打印这个矩阵,每次打印矩阵的一个圈,那么循环的终止条件是什么呢?

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

我们在来多列举几个例子观察下,例如:

  • 对于5*5的矩阵而言,最后一圈只有1个数字,对应的坐标为(2,2)
  • 对于6*6的矩阵而言,最后一圈有4个数字,其左上角的坐标依然为(2,2)

距上所述,我们可以发现:5 > 2 * 26 > 2 * 2全部成立,于是可以得出让循环终止的条件为:cols > start * 2 && rows > start * 2

接下来,我们来分析下如何实现打印一圈,前面的分析中我们已经知道了打印1圈需要4步,即:

  • 从左到右打印一行
  • 从上到下打印一列
  • 从右到左打印一行
  • 从下到上打印一列

每一步我们根据起始坐标和终止坐标用一个循环就能打印出一行或者一列,但是最后一圈有可能退化成只有一行、只有一列,甚至只有一个数字,因此打印这样的一圈就不再需要四步。可能只需要三步、两步甚至一步。

我们来分析下每一步的执行条件:

  • 第一步是必须的,因为打印一圈至少有一步

    • start作为行坐标
    • 从start位置开始遍历至终止列号,将其作为列坐标
    • 输出每一个元素

  • 第二步要求圈内至少有2行,即:终止行号大于起始行号

    • 从start+1位置遍历至至终止行号,将其作为行坐标
    • 终止列号作为列坐标
    • 输出每一个元素

  • 第三步要求圈内至少有两行两列,即:终止行号大于起始行号且终止列号大于起始列号

    • 从终止列号-1位置遍历至start,将其作为列坐标
    • 终止行号作为行坐标
    • 输出每一个元素

  • 第四步要求圈内至少有三行两列,即:终止行号比起始行号至少大2,同时终止列号大于起始列号

    • 从终止行号-1位置遍历至start+1位置,将其作为行坐标
    • start作为列坐标
    • 输出每一个元素

实现代码

经过上面的分析,我们已经有了缜密的逻辑,接下来我们就可以愉快的进行编码了,如下所示:

// 顺时针打印矩阵
export function PrintMatrix<T>(
  matrix: Array<Array<T>>,
  cols: number,
  rows: number
): void {
  if (matrix == null || cols == null || rows == null) return;
  // 圈数
  let start = 0;
  while (cols > start * 2 && rows > start * 2) {
    // 打印每一圈的数据
    PrintMatrixInCircle(matrix, cols, rows, start);
    start++;
  }
}
// 打印矩阵的一圈
function PrintMatrixInCircle<T>(
  matrix: Array<Array<T>>,
  cols: number,
  rows: number,
  start: number
): void {
  // 计算当前圈结束点坐标(索引从0开始,所以需要-1)
  // 终止列号
  const endX = cols - 1 - start;
  // 终止行号
  const endY = rows - 1 - start;
  // 从左到右打印一行
  for (let i = start; i <= endX; i++) {
    console.log(matrix[start][i]);
  }
  // 从上到下打印一列
  if (start < endY) {
    // 此时:
    //  最后一列已经在从左到右的打印中读取了
    for (let i = start + 1; i <= endY; i++) {
      console.log(matrix[i][endX]);
    }
  }
  // 从右到左打印一行
  if (start < endX && start < endY) {
    // 此时:
    //  最后一列已经在从上到下的打印中读取了
    for (let i = endX - 1; i >= start; i--) {
      console.log(matrix[endY][i]);
    }
  }
  // 从下到上打印一列
  if (start < endX && start < endY - 1) {
    // 此时:
    //  最后一列已经在从上到下的打印中读取了
    //  第一列的打印已经在从左到右的打印中读取了
    for (let i = endY - 1; i >= start + 1; i--) {
      console.log(matrix[i][start]);
    }
  }
}

我们用前面所举的例子来验证下上述代码能否正常执行,如下所示:

const matrix = [
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12],
  [13, 14, 15, 16]
];
PrintMatrix(matrix, 4, 4);

示例代码

本文所用代码完整版请移步:

PrintMatrix.ts

printMatrix-test.ts

以上就是TypeScript顺时针打印矩阵实现实例详解的详细内容,更多关于TypeScript顺时针打印矩阵的资料请关注我们其它相关文章!

(0)

相关推荐

  • java编程题之顺时针打印矩阵

    本文实例为大家分享了java顺时针打印矩阵的具体代码,供大家参考,具体内容如下 github:剑指offer编程题 import java.util.ArrayList; /** * * 剑指offer编程题(JAVA实现)--第19题:顺时针打印矩阵 * * 题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如, 如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,1

  • TypeScript中import type与import的区别详析

    目录 背景 import type vs import 使用 import type 的好处 参考链接 总结 背景 这周遇到了一个比较奇怪的问题:如何在 TypeScript 中根据某个 enum 的取值来执行后续逻辑? 按理来说应该很简单,这是 enum 的定义: export enum MyEnum { DEFAULT = 0, SOME_VALUE = 1, SOME_OTHER_VALUE = 2, } 然后在另一个项目中,通过 import type 来引入: import type

  • java实现的顺时针/逆时针打印矩阵操作示例

    java实现的顺时针/逆时针打印矩阵操作.分享给大家供大家参考,具体如下: public class SnakeMatrix { /** * 定义矩阵的阶数 */ private int n; //填充矩阵的值 private int k = 1; private int[][] data; /** * 定义矩阵移动的方向 */ public enum Direction { left, right, up, down, } SnakeMatrix(int n) { this.n = n; da

  • Java顺时针打印矩阵

    本文实例为大家分享了Java顺时针打印矩阵的具体代码,供大家参考,具体内容如下 题目: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字.例如:如果输入如下矩阵: 1     2       3     4 5     6       7     8 9    10    11   12 13 14    15   16 则依次打印出数字1.2.3.4.8.12.16.15.14.13.9.5.6.7.11.10. 思路: 首先拿到这个题,读完题我们脑子里会呈现出这样的一个画面.从外

  • typescript+vite项目配置别名的方法实现

    我们为了省略冗长的路径,经常喜欢配置路径别名.但是在typescript下会遇到一些坑,比如导入路径不能以“.ts”扩展名结束,路径不识别等.下面我记录了我的处理方法. vite.config.js: export default defineConfig({   resolve: {     alias: {       '@': path.resolve(__dirname, 'src') // 配置别名     }   } }) 配置完之后,就可以在ide中使用别名了.但是这个时候我发现,

  • Vue3+TypeScript+Vite使用require动态引入图片等静态资源

    问题:Vue3+TypeScript+Vite的项目中如何使用require动态引入类似于图片等静态资源! 描述:今天在开发项目时(项目框架为Vue3+TypeScript+Vite)需要 动态引入静态资源,也就是img标签的src属性值为动态获取,按照以往的做法直接是require引入即可,如下代码: <img class="demo" :src="require(`../../../assets/image/${item.img}`)" /> 写上后

  • TypeScript顺时针打印矩阵实现实例详解

    目录 前言 梳理思路 实现代码 示例代码 前言 有一个矩阵,如何按照从外向里以顺时针的顺序依次打印出每一个元素?本文将跟大家分享下这个算法,欢迎各位感兴趣的开发者阅读本文. 梳理思路 当我们遇到一个复杂的问题时,可以通过举例将它画出来,这样就可以更直观的发现规律.那么我们就先构造一个矩阵出来,如下所示: const matrix = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16] ]; 顺时针访问一个矩阵,那么它的访

  • TypeScript函数和类型断言实例详解

    目录 开始 断言 非空断言 类型断言 尖括号 as 确定赋值断言 类型守卫 trpeof in 函数 可选参数 默认值参数 函数重载 结束 开始 现在要加速学习了,大佬们有没有内推,给个推荐 会vue2/vue3 + ts 断言 非空断言 非空断言就是确定这个变量不是null或者undefined,就是把null或者undefined从他的类型中排除 function demo(message:string|undefined|null) { const str: string = messag

  • Android jni调试打印char阵列的实例详解

    Android jni调试打印char阵列的实例详解 前言: 在android开发中,用jni有时候需要打印某一个字符串的二进制格式输出,比较友好的输出格式是一个四列,八列,十六列的矩阵格式.类似在错误删除野指针时出现如下错误: pid: 2721, tid: 3005, name: pool-5-thread-5 >>> onxmaps.hunt <<< signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr dea

  • TypeScript 基本数据类型实例详解

    目录 TypeScript 介绍 类型分配 类型推导 数组 元组 object null 和 undefined 特殊类型 any unknown never void TypeScript 介绍 TypeScript 是 JavaScript 的超集,提供了 JavaScript 的所有功能,并提供了可选的静态类型.Mixin.类.接口和泛型等特性. TypeScript 的目标是通过其类型系统帮助及早发现错误并提高 JavaScript 开发效率. 通过 TypeScript 编译器或 Ba

  • springboot整合mybatis将sql打印到日志的实例详解

    在前台请求数据的时候,sql语句一直都是打印到控制台的,有一个想法就是想让它打印到日志里,该如何做呢? 见下面的mybatis配置文件: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-

  • Java打印流原理及实例详解

    这篇文章主要介绍了Java打印流原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 平时我们在控制台打印输出,是调用print方法和println方法完成的,这两个方法都来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输岀方式. PrintStream类 PrintStream类,为其他输出流添加了功能,使他们能够方便的打印各种数据值表示格式. PrintStream类的特点: 只负责数

  • java打印出菱形图案实例详解

    第一步:首先对图像进行解析 想要打印该图形必须要进行多层循环嵌套,分两个部分进行打印. 第一部分为上半部分前四行,他们是递增的关系,后半部分后三行为递减关系,由此可以得出我们需要写两个打的循环.并且由于"*"位置的关系,我们必须带入空格同时打印.所以每个部分需要两个循环控制,即两个大循环每个里面嵌套两个小循环总计四个循环. 第二部:对数字进行分析 在分析之前,我们必须明白外层循环控制行数,内层循环控制列数,因此我们需要分析他的行和列. 示例代码如下: class ForForTest

  • Python计算矩阵的和积的实例详解

    python的numpy库提供矩阵运算的功能,因此我们在需要矩阵运算的时候,需要导入numpy的包. 一.numpy的导入和使用 from numpy import *;#导入numpy的库函数 import numpy as np; #这个方式使用numpy的函数时,需要以np.开头. 二.矩阵的创建 由一维或二维数据创建矩阵 from numpy import *; a1=array([1,2,3]); a1=mat(a1); 创建常见的矩阵 data1=mat(zeros((3,3)));

  • 前端算法之TypeScript包含min函数的栈实例详解

    目录 前言 思路梳理 实现代码 示例代码 前言 基于数据结构: “栈”,实现一个min函数,调用此函数即可获取栈中的最小元素.在该栈中,调用min.push.pop的时间复杂度都是O(1). 本文就跟大家分享下这个算法,欢迎各位感兴趣的开发者阅读本文. 思路梳理 相信大多数开发者看到这个问题,第一反应可能是每次往栈中压入一个新元素时,将栈里的所有元素排序,让最小的元素位于栈顶,这样就能在O(1)的时间内得到最小元素了.但这种思路不能保证最后入栈的元素能够最先出栈,因此这个思路行不通. 紧接着,我

  • python之sqlalchemy创建表的实例详解

    python之sqlalchemy创建表的实例详解 通过sqlalchemy创建表需要三要素:引擎,基类,元素 from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column,Integer,String 引擎:也就是实体数据库连接 engine = create_engine('mysql+pymysql://go

随机推荐