华为OD机试 螺旋数字矩阵

一、题目描述

疫情期间,小明隔离在家,百无聊赖,在纸上写数字玩。他发明了一种写法:

给出数字个数 n (0 < n ≤ 999)和行数 m(0 < m ≤ 999),从左上角的 1 开始,按照顺时针螺旋向内写方式,依次写出2,3,…,n,最终形成一个 m 行矩阵。

小明对这个矩阵有些要求:

  1. 每行数字的个数一样多
  2. 列的数量尽可能少
  3. 填充数字时优先填充外部
  4. 数字不够时,使用单个 * 号占位
  5. 输入描述
  6. 两个整数,空格隔开,依次表示 n、m

1.1 输出描述

符合要求的唯一矩阵

1.2 用例

输入9
输出1 2 3
* * 4
9 * 5
8 7 6
说明9个数字写出4行,最少需要3列
输入3 5
输出1
2
3
*
*
说明3个数字写5行,只有一列,数字不够用*号填充
输入120 7
输出1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 19
45 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 63 20
44 83 114 115 116 117 118 119 120 * * * * * * 99 64 21
43 82 113 112 111 110 109 108 107 106 105 104 103 102 101 100 65 22
42 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 23
41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24"
说明

二、题目解析

本题需要我们将1~n数字按照螺旋顺序填入矩阵。

本题只给出了矩阵的行数m,没有给列数,需要我们求解一个最少的列数来满足矩阵能够填入n个数字,因此列数 k = ceil(n / m),这里的除法不是整除,并且要对除法的结果向上取整。

将数字1~n按照螺旋顺序,从矩阵matrix左上角开始填入,比较考察思维能力,具体实现如下:

  • 定义变量step,初始step=1,表示当前要填入的数字,因此step ≤ n
  • 定义变量x,y,初始x=0, y=0,表示要填值得矩阵位置,即初始时从矩阵左上角开始填入
    然后按照顺序循环进行下面四个填值操作:
  1. 正序填入第X行
  2. 正序填入第Y列
  3. 倒序填入第X行
  4. 倒序填入第Y列
    在这里插入图片描述

具体行为如下:

正序填入第x行
初始时,X,Y处于下面位置
在这里插入图片描述

按照螺旋顺序,我们应该正序填第X行,即此时行号X不变,列号Y++,具体操作是:

matrix[x][y++] = step++

当列号 Y >= k 时停止填值。如下图所示:此时 X = 0,Y = k
在这里插入图片描述

正序填入第y列
按照螺旋顺序,下一步我们应该做一次X++, Y–,让填值位置移动到(X,Y)位置
在这里插入图片描述

开始正序填第Y列,即此时列号Y保持不变,行号X++,具体操作是:

matrix[x++][y] = step++

当行号X >= m 时停止填值。如下图所示:此时X=m,Y = k - 1

在这里插入图片描述

倒序填入第x行
按照螺旋顺序,下一步我们应该做一次X–, Y–,让填值位置移动到(X,Y)位置

在这里插入图片描述

开始倒序填第X行,即此时行号X保持不变,列号Y–,具体操作是:

matrix[x][y--] = step++

当行号Y < 0 时停止填值。如下图所示:此时 X=m-1,Y = -1

在这里插入图片描述

倒序填入第y列
按照螺旋顺序,下一步我们应该做一次X–, Y++,让填值位置移动到(X,Y)位置

在这里插入图片描述

开始倒序填第Y列,即此时行号X–,列号Y保持不变,具体操作是:

matrix[x--][y] = step++

当行号X < 0 时停止填值。如下图所示:此时 X=-1,Y = 0

在这里插入图片描述

但是,此时不符合用例1要求,因为step只需要填到n即可,而用例1的n=9,因此填值过程中,我们需要增加一个判断,即step > n时彻底停止添值,即到下面状态时停止。
在这里插入图片描述

假设用例1修改为:

11 4

那么下面状态也是不对的

在这里插入图片描述

因为11覆盖掉了该位置添的值1,

因此填值过程如果发现,要添值位置已经有值了,比如下图X–后,发现(X,Y)位置已经填过值了,此时我们应该结束当前方向的添值

在这里插入图片描述

按照螺旋顺序,下一个添值位置应该如下图所示:

在这里插入图片描述

三、题目源代码

此时应该基于前一个状态进行X++,Y++,到达上图黄色位置后,此时又回到螺旋顺序的第一步,从第X行开始正序填入。

JS算法源码

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
 
void (async function () {
  // n 表示需要在螺旋矩阵中填入 1 ~ n 数字
  // m 是螺旋矩阵行数
  const [n, m] = (await readline()).split(" ").map(Number);
 
  // k 是螺旋矩阵列数
  const k = Math.ceil(n / m);
 
  // 螺旋矩阵,未填值位置默认值"*"
  const matrix = new Array(m).fill(0).map(() => new Array(k).fill("*"));
 
  // 当前要填入的值
  let step = 1;
 
  // 当前要填入的值的位置
  let x = 0;
  let y = 0;
 
  // 如果填入的值 > n,则停止填值,否则继续填
  while (step <= n) {
    // 正序填入第x行,即:行号不变,列号增加,注意:添值过程不能发生覆盖,也不能填入超过n的值
    while (y < k && matrix[x][y] == "*" && step <= n) matrix[x][y++] = step++;
    // 正序填完第x行后,y处于末尾越界位置,因此y需要退一步
    y -= 1;
    // 正序填完第x行来到第x行的末尾,即第y列,按照螺旋矩阵顺序,应该从第x+1行开始正序填值第y列
    x += 1;
 
    // 正序填入第y列,即:列号不变,行号增加,注意:添值过程不能发生覆盖,也不能填入超过n的值
    while (x < m && matrix[x][y] == "*" && step <= n) matrix[x++][y] = step++;
    x -= 1;
    y -= 1;
 
    // 倒序填入第x行,即:行号不变,列号减少,注意:添值过程不能发生覆盖,也不能填入超过n的值
    while (y >= 0 && matrix[x][y] == "*" && step <= n) matrix[x][y--] = step++;
    y += 1;
    x -= 1;
 
    // 倒序填入第y列,即:列号不变,行号减少,注意:添值过程不能发生覆盖,也不能填入超过n的值
    while (x >= 0 && matrix[x][y] == "*" && step <= n) matrix[x--][y] = step++;
    x += 1;
    y += 1;
  }
 
  // 打印螺旋矩阵字符串
  for (let i = 0; i < m; i++) {
    console.log(matrix[i].join(" "));
  }
})();

Java算法源码

import java.util.Scanner;
import java.util.StringJoiner;
 
public class Main {
 
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
 
    // 需要在螺旋矩阵中填入 1 ~ n 数字
    int n = sc.nextInt();
 
    // 螺旋矩阵行数
    int m = sc.nextInt();
 
    // 螺旋矩阵列数
    int k = (int) Math.ceil(n * 1.0 / m);
 
    // 螺旋矩阵
    int[][] matrix = new int[m][k]; // 由于需要填入1~n数字,因此这里未填值的位置值默认初始化为0
 
    // 当前要填入的值
    int step = 1;
 
    // 当前要填入的值的位置
    int x = 0;
    int y = 0;
 
    // 如果填入的值 > n,则停止填值,否则继续填
    while (step <= n) {
      // 正序填入第x行,即:行号不变,列号增加,注意:添值过程不能发生覆盖,也不能填入超过n的值
      while (y < k && matrix[x][y] == 0 && step <= n) matrix[x][y++] = step++;
      // 正序填完第x行后,y处于末尾越界位置,因此y需要退一步
      y -= 1;
      // 正序填完第x行来到第x行的末尾,即第y列,按照螺旋矩阵顺序,应该从第x+1行开始正序填值第y列
      x += 1;
 
      // 正序填入第y列,即:列号不变,行号增加,注意:添值过程不能发生覆盖,也不能填入超过n的值
      while (x < m && matrix[x][y] == 0 && step <= n) matrix[x++][y] = step++;
      x -= 1;
      y -= 1;
 
      // 倒序填入第x行,即:行号不变,列号减少,注意:添值过程不能发生覆盖,也不能填入超过n的值
      while (y >= 0 && matrix[x][y] == 0 && step <= n) matrix[x][y--] = step++;
      y += 1;
      x -= 1;
 
      // 倒序填入第y列,即:列号不变,行号减少,注意:添值过程不能发生覆盖,也不能填入超过n的值
      while (x >= 0 && matrix[x][y] == 0 && step <= n) matrix[x--][y] = step++;
      x += 1;
      y += 1;
    }
 
    // 打印螺旋矩阵字符串
    for (int i = 0; i < m; i++) {
      StringJoiner row = new StringJoiner(" ");
      for (int j = 0; j < k; j++) {
        if (matrix[i][j] == 0) {
          row.add("*");
        } else {
          row.add(matrix[i][j] + "");
        }
      }
      System.out.println(row);
    }
  }
}

Python算法源码

import math
 
# 输入获取
# n 表示需要在螺旋矩阵中填入 1 ~ n 数字
# m 表示螺旋矩阵行数
n, m = map(int, input().split())
 
 
# 算法入口
def getResult():
    # k是螺旋矩阵列数
    k = int(math.ceil(n / m))
 
    # 螺旋矩阵
    matrix = [['*'] * k for _ in range(m)]  # 未填值位置默认初始化为*
 
    # 当前要填入的值
    step = 1
 
    # 当前要填入的值的位置
    x = 0
    y = 0
 
    # 如果填入的值 > n,则停止填值,否则继续填
    while step <= n:
        # 正序填入第x行,即:行号不变,列号增加,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while y < k and matrix[x][y] == '*' and step <= n:
            matrix[x][y] = str(step)
            step += 1
            y += 1
 
        # 正序填完第x行后,y处于末尾越界位置,因此y需要退一步
        y -= 1
        # 正序填完第x行来到第x行的末尾,即第y列,按照螺旋矩阵顺序,应该从第x+1行开始正序填值第y列
        x += 1
 
        # 正序填入第y列,即:列号不变,行号增加,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while x < m and matrix[x][y] == '*' and step <= n:
            matrix[x][y] = str(step)
            step += 1
            x += 1
 
        x -= 1
        y -= 1
 
        # 倒序填入第x行,即:行号不变,列号减少,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while y >= 0 and matrix[x][y] == '*' and step <= n:
            matrix[x][y] = str(step)
            step += 1
            y -= 1
 
        y += 1
        x -= 1
 
        # 倒序填入第y列,即:列号不变,行号减少,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while x >= 0 and matrix[x][y] == '*' and step <= n:
            matrix[x][y] = str(step)
            step += 1
            x -= 1
 
        x += 1
        y += 1
 
    # 打印螺旋矩阵字符串
    for i in range(m):
        print(" ".join(matrix[i]))
 
 
# 算法调用
getResult()

C算法源码

#include <stdio.h>
#include <math.h>
 
int main() {
    // n 表示需要在螺旋矩阵中填入 1 ~ n 数字
    // m 表示螺旋矩阵行数
    int n, m;
    scanf("%d %d", &n, &m);
 
    // k 表示螺旋矩阵列数
    int k = (int) ceil(n * 1.0 / m);
 
    // 螺旋矩阵
    int matrix[m][k];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < k; j++) {
            matrix[i][j] = 0; // 由于需要填入1~n数字,因此这里未填值的位置值默认初始化为0
        }
    }
 
    // 当前要填入的值
    int step = 1;
 
    // 当前要填入的值的位置
    int x = 0;
    int y = 0;
 
    // 如果填入的值 > n,则停止填值,否则继续填
    while (step <= n) {
        // 正序填入第x行,即:行号不变,列号增加,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while (y < k && matrix[x][y] == 0 && step <= n) matrix[x][y++] = step++;
        // 正序填完第x行后,y处于末尾越界位置,因此y需要退一步
        y -= 1;
        // 正序填完第x行来到第x行的末尾,即第y列,按照螺旋矩阵顺序,应该从第x+1行开始正序填值第y列
        x += 1;
 
        // 正序填入第y列,即:列号不变,行号增加,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while (x < m && matrix[x][y] == 0 && step <= n) matrix[x++][y] = step++;
        x -= 1;
        y -= 1;
 
        // 倒序填入第x行,即:行号不变,列号减少,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while (y >= 0 && matrix[x][y] == 0 && step <= n) matrix[x][y--] = step++;
        y += 1;
        x -= 1;
 
        // 倒序填入第y列,即:列号不变,行号减少,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while (x >= 0 && matrix[x][y] == 0 && step <= n) matrix[x--][y] = step++;
        x += 1;
        y += 1;
    }
 
    // 打印螺旋矩阵字符串
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < k; j++) {
            if (matrix[i][j] == 0) {
                printf("*");
            } else {
                printf("%d", matrix[i][j]);
            }
 
            if (j < k - 1) {
                printf(" ");
            }
        }
        puts("");
    }
 
    return 0;
}

C++算法源码

#include <bits/stdc++.h>
using namespace std;
int main() {
    int n, m;
    cin >> n >> m;
 
    int k = n / m + (n % m ? 1 : 0);
 
    vector<vector<int>> matrix(m, vector<int>(k, 0));
 
    int step = 1;
 
    int x = 0;
    int y = 0;
 
    // 如果填入的值 > n,则停止填值,否则继续填
    while (step <= n) {
        // 正序填入第x行,即:行号不变,列号增加,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while (y < k && matrix[x][y] == 0 && step <= n) matrix[x][y++] = step++;
        // 正序填完第x行后,y处于末尾越界位置,因此y需要退一步
        y -= 1;
        // 正序填完第x行来到第x行的末尾,即第y列,按照螺旋矩阵顺序,应该从第x+1行开始正序填值第y列
        x += 1;
 
        // 正序填入第y列,即:列号不变,行号增加,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while (x < m && matrix[x][y] == 0 && step <= n) matrix[x++][y] = step++;
        x -= 1;
        y -= 1;
 
        // 倒序填入第x行,即:行号不变,列号减少,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while (y >= 0 && matrix[x][y] == 0 && step <= n) matrix[x][y--] = step++;
        y += 1;
        x -= 1;
 
        // 倒序填入第y列,即:列号不变,行号减少,注意:添值过程不能发生覆盖,也不能填入超过n的值
        while (x >= 0 && matrix[x][y] == 0 && step <= n) matrix[x--][y] = step++;
        x += 1;
        y += 1;
    }
 
    // 打印螺旋矩阵字符串
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < k; j++) {
            if (matrix[i][j] == 0) {
                cout << "*";
            } else {
                cout << matrix[i][j];
            }
 
            if (j < k - 1) {
                cout << " ";
            }
        }
        cout << endl;
    }
 
    return 0;
}
### 回答1: 华为OD机试的稀疏矩阵问题是一个经典的矩阵优化问题。稀疏矩阵是指由很多元素为零的矩阵。为了减少存储空间和计算量,我们可以采用稀疏矩阵的压缩表示方法。 一种常用的表示方法是使用三元组表示法。三元组表示法将稀疏矩阵中非零元素的值、所在的行和列分别存储起来。这样就可以只存储非零元素,节省存储空间。同时,由于零元素较多,所以计算稀疏矩阵的时候可以跳过零元素的计算,减少了计算量。 在处理稀疏矩阵时,常见的操作包括转置、相加、相乘等。对于转置操作,只需要将每个非零元素的行和列进行交换即可。对于相加操作,对应行列的元素相加即可。而对于相乘操作,则需要根据矩阵乘法的规则进行计算,但只需要计算非零元素的乘积,跳过零元素的计算。 使用稀疏矩阵的优点是在存储和计算方面都能获得较大的优势,节省了存储空间和计算时间。特别是在处理大规模的矩阵时,稀疏矩阵的优势更加明显。 总之,稀疏矩阵是一种通过压缩表示的优化技术,可以节省存储空间和计算时间。在华为OD机试中,掌握稀疏矩阵的表示方法和相关操作,能够有效解决大规模矩阵的存储和计算问题,具有重要的实际意义。 ### 回答2: 稀疏矩阵是指其中大部分元素为零的矩阵。在实际应用中,许多数据都是稀疏的,例如文本数据、社交网络等。稀疏矩阵的存储和计算是一个重要的问题。 对于稀疏矩阵的存储,主要有三种方法:顺序存储、链表存储和三元组顺序表存储。顺序存储是将矩阵逐行或逐列依次存入一个一维数组中,由于大部分元素为零,会带来很多冗余。链表存储使用链表的方式存储非零元素,可以节省存储空间,但查找非零元素的效率较低。三元组顺序表存储是最常用的一种方法,它将非零元素的行列信息和数值依次存放在一个三元组中,再按照非零元素的行或列的大小进行排序存储。 对于稀疏矩阵的计算,主要采用矩阵的压缩存储方式来提高计算效率。例如矩阵的乘法运算,可以利用三元组顺序表存储的方式,通过稀疏矩阵的特点来减少计算量。具体操作是遍历两个稀疏矩阵的非零元素,将相同位置的元素相乘累加,得到新的矩阵的非零元素。 稀疏矩阵的应用非常广泛,涉及到很多领域,如图像处理、数据挖掘、网络分析等。稀疏矩阵的存储和计算方法对提高算法的效率和节约存储空间非常重要。因此,对于华为OD机试中的稀疏矩阵问题,需要掌握稀疏矩阵的存储方法和计算方法,并能灵活运用在实际问题中。 ### 回答3: 稀疏矩阵是指矩阵中大部分元素为零的矩阵。相比于稠密矩阵,稀疏矩阵在存储和计算上具有一定的优势。 首先,稀疏矩阵的存储方式可以优化空间利用率。稠密矩阵需要存储所有元素,而稀疏矩阵只需存储非零元素及其位置信息,可以减少存储空间的消耗。例如,可以通过使用三元组表示法或者压缩存储方式来存储稀疏矩阵,使得矩阵的存储空间大幅减少。 其次,稀疏矩阵的计算效率也较高。因为稀疏矩阵的大部分元素为零,可以通过跳过这些零元素来加快计算速度。对于一些特定的矩阵运算,如矩阵乘法和矩阵加法,针对稀疏矩阵算法可以显著减少计算量和存储需求。此外,还可以通过并行计算等技术来进一步提高稀疏矩阵的计算效率。 稀疏矩阵在很多领域有广泛的应用,如图像处理、网络建模、自然语言处理等。在图像处理中,往往会遇到大型图像矩阵,其中很多像素点都是零,因此可以将图像表示为稀疏矩阵进行处理;在网络建模中,可以使用稀疏矩阵表示节点之间的连接关系,从而分析网络的拓扑结构和特性;在自然语言处理中,可以使用稀疏矩阵来表示词汇之间的相关性,进行文本分析和语义处理。 综上所述,稀疏矩阵在存储和计算上具有优势,广泛应用于各个领域。对于华为OD机试来说,理解和掌握稀疏矩阵的存储表示和相关算法,将对解题有一定的帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

N阶二进制

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值