蛇形/回形矩阵(超详细!看了不会你来打我)

2023-11-05

回型矩阵

给你一个整数n,按要求输出n∗n的回型矩阵
例如输入n=4,输出如下:
在这里插入图片描述

分析

回形矩阵的填充轨迹如下所示:
在这里插入图片描述

填充顺序:

最上面的行——>最右边的列——>最下面的行——>最左边的列——>最上面的行——>……

首先,我们可以看出,填充轨迹存在大小不等的回形,我称之为外回内回

如何控制外回结束后,会进入内回?

需要4个变量作为边界限制条件,随着外回的进行,不断缩紧边界限制条件,逐步迫使轨迹进入内回。具体设置如下所示:
在这里插入图片描述
设置了这4个限制条件还不够哦!因为这4个条件只会限制回的轨迹,但并不适合用来控制数字的写入!为什么这么说?看:

假设现在利用边界限制条件去控制数字写入:
第一行的写入过程如下:
在这里插入图片描述

现在需要输入最右边的列,top很明显需要更新,假设我们更新了top
在这里插入图片描述
接下来输入最右边的列:
在这里插入图片描述
那么现在问题来了!

在这里插入图片描述
按理说,当top==bottom并且left==right时,矩阵应该已经被填充完成,而此时我们竟然只填充了6个格子!还没开始就结束了!令人猝不及防。

就算我们之后可以通过什么神奇的方法将4个条件恢复,必然也会导致复杂的逻辑,划不来!

上面大概解释了4个边界条件不能用来控制数字写入的原因,接下来就谈谈正确的解答姿势!

我们再引入4个变量l,r,b,t去控制数字的写入

先是最上面的行,令l=left,而后在l<=right的条件下,++l一直执行,同时输入数字。当最后一个数字填入时,我们令++top,上界下移。

在这里插入图片描述
然后是最右边面的列,令t=top,而后在t<=bottom的条件下,++t一直执行,同时输入数字。当最后一个数字填入时,我们令--right,右界左移。
在这里插入图片描述
然后是最下面的行,令r=right,而后在r>=left的条件下,--r一直执行,同时输入数字。当最后一个数字填入时,我们令--bottom,下界上移。
在这里插入图片描述
然后是最左边的列,令b=bottom,而后在b>=top的条件下,--b一直执行,同时输入数字。当最后一个数字填入时,我们令++left,左界右移。
在这里插入图片描述
现在就剩下一个2*2的矩阵了,和上面一样的执行流程,既然是一样的,那么逻辑相同,循环解决!
在这里插入图片描述

code

上面解释的挺详细了,代码就不注释了

#include <iostream>
#include <vector>
using namespace std;
class Solutions{
public:
    void ShowMatrix(const vector<vector<int>>& matrix) {
        int n = matrix.size();
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j)
                printf("%4d ", matrix[i][j]);
            cout << endl;
        }
    }
    vector<vector<int>> Clip(const int& n) {
        vector<vector<int>> clip(n, vector<int>(n));
        int left = 0, top = 0, right = n - 1, bottom = n - 1;
        int l, r, b, t;
        int num = 1;
        while (num <= n * n) {//循环条件可换top==bottom && left==right
            l = left;
            while (l <= right)
                clip[top][l++] = num++;
            ++top;
            t = top;
            while (t <= bottom)
                clip[t++][right] = num++;
            --right;
            r = right;
            while (r >= left)
                clip[bottom][r--] = num++;
            --bottom;
            b = bottom;
            while (b >= top)
                clip[b--][left] = num++;
            ++left;
        }
        return clip;
    }
};
int main() {
    int n;
    cin >> n;
    Solutions s;
    vector<vector<int>> m(n, vector<int>(n));
    m = s.Clip(n);
    s.ShowMatrix(m);
    return 0;
}

【注】:代码并没有对异常输入进行控制!不可输入负数!

效果

在这里插入图片描述在这里插入图片描述

蛇形矩阵

给你一个整数n,输出n∗n的蛇形矩阵。
例如输入n=4,输出如下:
在这里插入图片描述

分析

蛇形矩阵的填充轨迹如下所示:

在这里插入图片描述
填充规律:

斜向上——>斜向下——>斜向上——>……

如何控制斜向上/下

边界的控制不可避免,如下图所示,格子中的箭头表示这个字是在哪个方向被填充数字的,还有一圈虚线画出的格子,称之为虚界

虚界在矩阵中并不存在,但当矩阵的索引进入虚界,说明索引非法!

但换个角度想,一旦索引进入虚界,说明正在填充方向的格子已经全部填充,需要换方向了!

所以说虚界的意义在于控制方向的转换!如回型矩阵中的4个边界条件一般。
在这里插入图片描述
由上图可以轻松看出,两个方向的控制极其简单(假设矩阵名为s,横坐标为x,纵坐标为y):

斜向上s[x--][y++]
斜向下s[x++][y--]

确定了沿方向填充的语句,填充完成,下一步就是转换方向,索引必须进入虚界方可。下图展示两个方向在填充时会进入的虚界。

在这里插入图片描述
认真观察即可发现虚界与正确索引的校正关系!如下所示:
观
此处要分类讨论:

位置\校正操作\填充方向 斜向上 斜向下
上三角 ++x ++y
下三角 x+=2,--y y+=2,--x

根据上表我们可以将进入虚界的索引校正回来,然后进行下一个方向的填充!但真的是这样吗?

请注意主对角线的处理,你是将它看成上三角的一部分还是下三角的一部分?

这决定我们在切换上/下三角时需不需要进行额外的校正操作!

如果你将它看成下三角的一部分,那么恭喜你,你不需要额外进行校正。而如果将它看成上三角的一部分,那么你需要校正!

为简单起见(且这也可以通过图示看出来为什么要将主对角线看成下三角的一部分,因为主对角线的校正方法很明显属于下三角),我们将主对角线划归下三角,就不化简为繁了(虽然只会多一个if else结构,但我就是不想加,哎)

最后一个阶段了!我们此时要确定到底什么时候是斜向上?什么时候是斜向下?

设置计数器k,从0开始计数。下图每个格子右下角表示k的值
在这里插入图片描述
可以轻易看出,当k为奇数时,方向为斜向下,为偶数时为斜向下!这不随输入矩阵维数n变化!

蛇形矩阵的逻辑就这么完了!图示过程如下:
在这里插入图片描述

code

#include <iostream>
#include <vector>
using namespace std;
class Solutions{
public:
    vector<vector<int>> Snake(const int& n) {
        vector<vector<int>> snake(n, vector<int>(n));
        int num = 1;
        int x = 0, y = 0;
        int flag;
        for (int k = 0; k < 2 * n; ++k) {
            flag = k >= n - 1 ? 1 : 0;
            if (!flag) {//上三角
                if (!(k & 1)) {//斜向上
                    while (x >= 0)
                        snake[x--][y++] = num++;
                    ++x;
                }
                else {//斜向下
                    while (y >= 0)
                        snake[x++][y--] = num++;
                    ++y;
                }
            }
            else {//下三角
                if (!(k & 1)) {//斜向上
                    while (y < n)
                        snake[x--][y++] = num++;
                    x += 2, --y;
                }
                else {//斜向上
                    while (x < n)
                        snake[x++][y--] = num++;
                    y += 2, --x;
                }
            }
        }
        return snake;
    }
    void ShowMatrix(const vector<vector<int>>& matrix) {
        int n = matrix.size();
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j)
                printf("%4d ", matrix[i][j]);
            cout << endl;
        }
    }
};
int main() {
    int n;
    cin >> n;
    Solutions s;
    vector<vector<int>> m(n, vector<int>(n));
    m = s.Snake(n);
    s.ShowMatrix(m);
    return 0;
}

效果

在这里插入图片描述
在这里插入图片描述

结语

有时候做题,我们需要深入剖析里面的逻辑,要搞清楚为什么这样是正确的,那样是不正确的。只有深入了解里面的各种逻辑,我们才能写出比较好的代码。

更新——蛇形矩阵另一种的解题方法

该解法来自一位王姓妹纸!使用java完成,支持非正方形蛇形矩阵,感兴趣的童鞋可以仔细研究一下:

static int count = 0;
public static int[][] SnakePrintArr(int m, int n)
{
	if (m == 0 || n == 0)
		return null;
	int x1 = 0;
	int x2 = 0;
	int y1 = 0;
	int y2 = 0;
	boolean fromUp = true;
	int[][] arr = new int[m][n];
	while (y2 < m){
		fromUp = !fromUp;
		PrintALine(arr, x1, x2, y1, y2, fromUp);
		x1 = (y1 == arr[0].length - 1) ? ++x1 : x1;
		y1 = (y1 == arr[0].length - 1) ? y1 : ++y1;
		y2 = (x2 == arr.length - 1) ? ++y2 : y2;
		x2 = (x2 == arr.length - 1) ? x2 : ++x2;
		//System.out.println(x1);
	}
	return arr;
}
public static void PrintALine(int[][] arr, int x1, int x2, int y1, int y2, boolean fromUp){
	if (fromUp)
		while (x1 <= x2)
			arr[x1++][y1--] = ++count;
	else
		while (x2 >= x1)
			arr[x2--][y2++] = ++count;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

蛇形/回形矩阵(超详细!看了不会你来打我) 的相关文章

  • tar命令如何解压指定文件到指定目录下

    举一个例子 解压 a tar gz 包里文件名以 one 开头的文件到 tmp 文件夹下 tar xzv C tmp f a tar gz one
  • FBXSDK2018 plugin for Unity

    1 下载FBXSDK 点击打开链接 2 安装SDK 记住你所安装的目录 3 visualstudio 新建 C 空项目 首先配置 C C 附加包含目录 你安装sdk 路径下的include 4 设置预处理器 假设是Debug x64 WIN

随机推荐

  • 原地逆转链表的多种方案

    原地逆转链表的多种方案 include
  • 正大期货:期货交易规则和操作方法?

    1 实行t 0的交易方式 即投资者当天买入的期货 在当天就能卖出 2 双向交易 即投资者可以进行做多操作 也可以进行做空交易 3 保证金制度 即投资者交易期货需要交纳一定比例的保证金 4 强制平仓制度 即当投资者的保证金不足时 期货公司为了
  • java获取微信用户信息(UnionID)

    本篇主要是针对用户关注公众号 然后利用接口获取用户的信息包括unionid信息 首先就是获取微信access token的值 官方文档 https mp weixin qq com wiki t resource res main id m
  • rockchip rk3368(px5)车载开发之路2,屏幕正常显示(不对的地方是UI)

    本系列记载作者来到一个新的车载后装市场小公司 负责从新开始维护一套代码的心路过程 系统使用瑞芯微的rk3368芯片 版本是PX5 Android 8 0 release 20180726 从无到有的每个patch修改以及思考 其中着重点是驱
  • 不好意思,list.contain 去重该换换了!

    程序员的成长之路 互联网 程序员 技术 资料共享 关注 阅读本文大概需要 3 5 分钟 来自 blog csdn net qq 35387940 article details 129885310 最近又是一轮代码review 发现了一些实
  • 法宣在线积分小程序python学满指定分钟数自动关闭

    微信 法宣在线积分学习小程序 可自动学 有不明白的可以联系我 这种只是辅助 不能一天刷很多 比如一天100多分就可以了不要太多 不然会被查 如果没电脑的 可以发账号给我 我把法宣在线的账号登录上每天自动积分就可以了 电脑端exe 打包下载
  • Memcached简单介绍

    介绍 Memcached 是一个高性能的分布式内存对象缓存系统 用于动态Web应用以减轻数据库负载 它通过在内存中缓存数据和对象来减少读取数据库的次数 从而提高动态 数据库驱动网站的速度 Memcached基于一个存储键 值对的hashma
  • flutter 导出iOS问题2

    问题1 The Swift pod FirebaseCoreInternal depends upon GoogleUtilities which does not define modules To opt into those targ
  • Vue 之 Toast 消息提示插件的简单封装

    Vue 之 Toast 消息提示插件的简单封装 目录 Vue 之 Toast 消息提示插件的简单封装 一 简单介绍 二 实现原理 三 注意事项 四 效果预览 五 实现 六 项目源码 一 简单介绍 Vue 开发的一些知识整理 方便后期遇到类似
  • vue 报错:Cannot read property 'xxx' of undefined",但是页面能渲染上数据

    有时候会遇到给页面绑定数据的时候 可以绑定成功 但vue warn xxx属性of undefined 如果本组件只是绑定简单的数据倒是可以忽略 如果本组件还引入了其他组件或第三方组件 插件 则就渲染不出来 就需要解决了
  • SQL WHERE语句

    文章目录 WHERE基础语法 WHERE AND OR WHERE ORDER BY ORDER BY ORDER BY ASC DESC ORDER BY 多列 WHERE基础语法 SELECT FROM table name WHERE
  • npm run dev 报错:missing script:dev

    在 npm run dev 或 npm start 报错 打开package js 发现没有script 里面的内容 本应该有如图内容 解决方法 1 vue init webpack package js文件中会添加内容 2 npm run
  • C# ThreadPool 线程池

    线程 被定义为程序的执行路径 每个线程都定义了一个独特的控制流 如果您的应用程序涉及到复杂的和耗时的操作 那么设置不同的线程执行路径往往是有益的 每个线程执行特定的工作 线程是轻量级进程 一个使用线程的常见实例是现代操作系统中并行编程的实现
  • IPv4地址分类(A类 B类 C类 D类 E类)

    5类地址 A类 B类 C类 D类 E类 IPv4地址由四段组成 每个字段是一个字节 8位 最大值是255 IPv4地址由两部分组成 即网络地址和主机地址 网络地址表示其属于互联网的哪一个网络 主机地址表示其属于该网络中的哪一台主机 二者是主
  • 在windows上配置git支持多账号

    1 背景 现在大多数人都采用git进行版本管理 在git下面进行开发被越来越多的程序员所接受 还有越来越多的人参与开源社区的建设 现在有一个问题就是 在windows环境下 如何在git客户端上通过ssh key的方式配置多个账号 不需要输
  • 算法也要面向对象OO

    直接去模糊的去写 通过调试 一步步改 就算最后写出来了也不知道怎么写出来的 一定要先有整体思路 面向操作会很凌乱 算法也要面向对象 识别出变量 定义有确切含义的变量 以及这边变量之间互动的关系 时刻维护变量意义的正确性 也就是invaria
  • Flutter项目——静态页面布局4详情页

    详情页 override Widget build BuildContext context return Scaffold appBar AppBar widget代表了我们的 MovieDetail 这个类 当前类是控制器 需要用 wi
  • python模拟点击网页按钮_网页自动化开发(第一章)

    Web网页可以用许多工具进行开发 本文重点是介绍如何在python中使用Selenium实现网页自动化开发 主要先介绍Selenium的概念 开发环境搭建 selenium模拟用户打开浏览器并实现自动操作浏览的网页 比较适用于seleium
  • Centos7如何安装图形化界面 and 设置开机默认进入图形化界面

    因为VMware安装虚拟机的时候默认是最小安装的 所以没有图形化界面 这样将本机文件转移到虚拟机上的时候特别不方便 而装好图形化界面之后只需在本机复制 crtl c 然后在虚拟机中对应位置右键paste即可 1 打开命令行 输入 yum y
  • 蛇形/回形矩阵(超详细!看了不会你来打我)

    回型矩阵 给你一个整数n 按要求输出n n的回型矩阵 例如输入n 4 输出如下 分析 回形矩阵的填充轨迹如下所示 填充顺序 最上面的行 gt 最右边的列 gt 最下面的行 gt 最左边的列 gt 最上面的行 gt 首先 我们可以看出 填充轨