【力扣】Z字形变换,模拟+直接构造

Z字形变换原题地址

方法一:利用二维矩阵模拟

对于特殊情况,z字形变换后只有一行或只有一列,则变换后的字符串和原字符串相同。

对于一般情况,我们可以考虑按照题目要求,把字符串按照Z字形存储到二维数组中,再横向遍历所有有效字符

假设Z字形变换后的矩阵有r行,字符串的长度为n。

Z字形变换是按照周期t先向下,再向右上运动。一个周期t=r+(r-2)=r*2-2

其中r-2不包含两个红圈的位置。 一个周期t内的行数为r行,列数为1+(r-2)=r-1列,即最左边的一列以及中间的r-2列。矩阵的周期数为(n/t)向上取整,即(n+t-1)/t,加上的t-1是为了向上取整。矩阵的总列数为周期数*每个周期的列数,即c=(n+t-1)/t*(r-1)

那么,什么时候向下走,什么时候向右上方走呢?这要看当前处在周期的什么位置。假设当前遍历到下标为i的字符,如果imodt<r-1,即当前处在周期的前r-1个位置,就需要向下走,否则就要向右上方走

// 方法一:利用二维矩阵模拟
class Solution {
public:string convert(string s, int numRows) {int n = s.size();int r = numRows; // 行数// 只有一行或者只有一列if (r == 1 || r >= n)return s;// 周期t=r+r-2int t = r * 2 - 2;// 一共有 (n/t)向上取整 个周期// 即(n+t-1)/t个周期// 每个周期有1+r-2=r-1列int c = (n + t - 1) / t * (r - 1); // 列数// 构造矩阵,即r个string的数组,每个string的长度为cvector<string> mat(r, string(c, 0));int x = 0, y = 0; // 左上角for (int i = 0; i < n; ++i){mat[x][y] = s[i];// 周期前r-1次都是向下移动// 否则向右上方移动if (i % t < r - 1){++x;}else{--x;++y;}}string ans;// 拼接每行有效字符for (auto& row : mat){for (auto ch : row){if (ch)ans += ch;}}return ans;}
};

方法二:压缩矩阵空间

模拟时,可以不按照Z字形存储到矩阵中,而是根据当前字符在第几行,就存储在该行的最后一个位置,即尾插到当前行。这样的话可以节省矩阵的空间。

如果采用这种方案,就只需要考虑是向下走还是向上走。按照相同的思路,当imodt<r-1,即当前周期的前r-1个字符,需要向下走,反之就向上走。

// 方法二:压缩矩阵空间
class Solution {
public:string convert(string s, int numRows) {int n = s.size();int r = numRows; // 行数// 只有一行或只有一列if (r == 1 || r >= n)return s;vector<string> mat(r);// 周期t=r+r-2int t = r * 2 - 2;int x = 0; // 在第几个string后面添加字符for (int i = 0; i < n; ++i){mat[x] += s[i];// 每个周期前r-1次向下移动if (i % t < r - 1)++x;else--x;}string ans;// 拼接所有行for (auto& row : mat){ans += row;}return ans;}
};

方法三:方法二的另一种写法

在考虑是向下走还是向上走时,可以不用计算在当前周期的第几个位置,而是直接判断当前所处位置是否在最上面还是最下面。也就是说,如果当前在第x行,若x==1或者x==r-1,说明要转向本来是向下走就要转为向上走,本来是向上走就要转为向下走

我们可以定义一个flag,如果flag=1代表向下走,flag=-1代表向上走,每次只需要x+=flag就能求出新的所在行x了。如果要转向,只需执行flag=-flag

// 方法三:方法二的另一种写法,利用flag记录何时转向
class Solution {
public:string convert(string s, int numRows) {int n = s.size();int r = numRows; // 行数// 只有一行或只有一列if (r == 1 || r >= n)return s;vector<string> mat(r);int x = 0; // 在第几个string后面添加字符int flag = 1; // 行转向标志,1代表向下走,-1代表向上走for (int i = 0; i < n; ++i){mat[x] += s[i];x += flag;// 转向if (x == r - 1 || x == 0)flag = -flag;}string ans;// 拼接所有行for (auto& row : mat){ans += row;}return ans;}
};

方法四:直接构造

前三种方法都需要构造一个新的矩阵来模拟,我们可以考虑直接构造,也就是直接取出原字符串的字符来构造ans字符串。这就需要找出Z字形变换的规律,看图:

按照“Z字形”的顺序来看,就是0->1->2->3->...->t-2->t-1->t->t+1->t+2->...->2t-2->2t-1->2t->2t+1->2t+2->...

如果我们横着看呢? 我们用i来控制行,i从0递增到r-1。再用j控制列,j从0开始,每次递增t,也就是0,t,2t,3t,...。那么下图中,每个周期都是线+方框,线是i+j,框柱的是j+t-i

对于每一行,都有线,但是第0行和第r-1行没有方框内的元素,利用这点直接构造字符串即可。

// 方法四:直接构造
class Solution {
public:string convert(string s, int numRows) {int n = s.size();int r = numRows; // 行数// 只有一行或只有一列if (r == 1 || r >= n)return s;string ans;// 周期t=r+r-2int t = r * 2 - 2;for (int i = 0; i < r; ++i){for (int j = 0; j + i < n; j += t){// 当前周期第一个字符ans += s[j + i];// 若不是第一行和最后一行,还有第二个字符if (0 < i && i < r - 1 && j + t - i < n)ans += s[j + t - i];}}return ans;}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/455538.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis之环境搭建以及实现增删改查

MyBatis之环境搭建以及实现增删改查 前言准备工作1.保证数据库已启动2. 创建Person表 MyBatis开发环境搭建1.下载MyBatis jar包2.下载MySQL的JDBC驱动3.新建Java工程&#xff08;Java8&#xff09;&#xff0c;导入MyBatis的jar包以及JDBC驱动 实现步骤1. 创建Peron类2. 编写Ma…

Python根据文件后缀整理文件夹

文章目录 文件夹类型字典移动文件主流程 此前用Python实现了根据文件后缀整理文件夹的方法&#xff0c;见此文&#xff1a;Python根据文件后缀整理文件夹。但这篇博客并没有进行良好的封装&#xff0c;下面仍以文件夹整理为目的&#xff0c;用类来重新实现次功能。 文件夹类型…

13. Threejs案例-绘制3D文字

13. Threejs案例-绘制3D文字 实现效果 知识点 FontLoader 一个用于加载 JSON 格式的字体的类。 返回 font&#xff0c;返回值是表示字体的 Shape 类型的数组。 其内部使用 FileLoader 来加载文件。 构造器 FontLoader( manager : LoadingManager ) 参数类型描述managerLo…

idea运行程序报错 java 程序包org.junit不存在

在 IntelliJ IDEA 中运行程序时遇到错误提示&#xff1a;“java: 程序包org.junit不存在”&#xff0c;针对这一问题&#xff0c;我们可以考虑以下三步来解决&#xff1a; 第一步&#xff1a;检查JUnit依赖 尽管现代项目创建时通常会默认引入JUnit依赖&#xff0c;但仍需检查…

算法学习——LeetCode力扣哈希表篇2

算法学习——LeetCode力扣哈希表篇2 454. 四数相加 II 454. 四数相加 II - 力扣&#xff08;LeetCode&#xff09; 描述 给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 …

华清远见嵌入式学习——春节作业——2.6日

作业要求&#xff1a; 作业答案&#xff1a; 作业代码效果图 作业代码截图 作业代码 #include <myhead.h>//通过无名信号量实现线程间的同步 //定义三个无名信号量 sem_t sem1; sem_t sem2; sem_t sem3;//线程A 打印 Happy void *A(void *arg) {int n 5;while(n--){s…

从小白到入门webrtc音视频通话

0. 写在前面 先会骑车&#xff0c;再研究为什么这么骑&#xff0c;才是我认为学习技术的思路&#xff0c;底部付了demo例子&#xff0c;根据例子上面的介绍即可运行。 1. 音视频通话要用到的技术简介 websocket 介绍&#xff1a;1. 服务器可以向浏览器推送信息&#xff1b;2…

第十二章[模块]:12.2:模块的加载

一,导入模块要搜索的路径 1,要搜索的路径有哪些? 当前程序的执行目录。 环境变量 PYTHONPATH(如果设置了的话)指定的目录列表。 安装 Python 时配置的相关目录列表 2,得到具体的模块搜索目录 import sysfor path in sys.path:print(path) 运行结果 (macos平台): /Us…

安装PyInstaller的保姆级教程

一、安装PyInstaller之前首先要安装Python&#xff0c;小编这里安装的是Python3.9&#xff0c;目前&#xff08;2024/2/6&#xff09;匹配到的最高版本的PyInstaller的版本为6.3.0。需要安装Python的小伙伴可以去这里安装python详细步骤&#xff08;超详细&#xff0c;保姆级&a…

【ETOJ P1036】我踏马吃吃吃吃吃 题解(优先队列+贪心算法)

题目描述 有n个人在m个窗口打饭&#xff0c;因为每个人的需求不同&#xff0c;所以每个人的“窗口占用时间”也不同。第i个人的窗口占用时间为 t i t_i ti​。 请问如何安排这些人到窗口打饭&#xff0c;可以使得所有人等待的时间之和最小&#xff1f; 输入格式 第一行两个…

Linux 网络:PTP 简介

文章目录 1. 前言2. PTP(Precision Time Protocol​) IEEE 1588 协议简介2.1 PTP IEEE 1588 协议时间同步原理2.2 PTP IEEE 1588 协议时钟类型2.2.1 普通时钟(OC: Ordinary Clock)2.2.2 边界时钟(BC: Boundary Clock)2.2.3 透明时钟(TC: Transparent Clock)2.2.3.1 端对端透明时…

769933-15-5,Biotin aniline,用来标记和检测细胞膜上的特定蛋白质

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;769933-15-5&#xff0c;Biotin aniline&#xff0c;生物素苯胺 一、基本信息 产品简介&#xff1a;Biotin aniline, also known as Biotin aniline, is a molecular probe with strong reactivity. Its uniqueness…