【力扣】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 列。矩阵的周期数为 \left \lceil \frac{n}{t} \right \rceil ,即 (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/463440.html

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

相关文章

Java多线程:单例模式

&#x1f451;专栏内容&#xff1a;Java⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、饿汉模式二、懒汉模式&#xff08;单线程&#xff09;三、懒汉模式&#xff08;多线程&#xff09; 单例模式是最常见的设计…

115.乐理基础-五线谱-五线谱的练习方式

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;114.乐理基础-五线谱-快速识别五线谱的谱号-CSDN博客 前置知识&#xff1a;视频地址 乐理基础视频版&#xff0c;文字版 乐理基础文字版 快速记忆五线谱的方式不要去学&#xff0c;就机械式练习&#xff0c;练习时…

Bean 的作用域

Bean 的作用域种类 在 Spring 中⽀持 6 种作⽤域&#xff0c;后 4 种在 Spring MVC 环境才⽣效 1. singleton&#xff1a;单例作⽤域 2. prototype&#xff1a;原型作⽤域&#xff08;多例作⽤域&#xff09; 3. request&#xff1a;请求作⽤域 4. session&#xff1a;会话作⽤…

【 buuctf snake 】

需要用到 Serpent 加密&#xff0c;蛇也不一定是 snake&#xff0c;serpent 也是蛇的意思。 binwalk -e /Users/xxx/Downloads/snake/snake.jpgbinwalk 提取 key 中有 base64 编码&#xff0c;解密 图源自BUUCTF:snake_buuctf snake-CSDN博客 结果是 anaconda&#xff0c;还有…

ESP8266 tcpsocket透传模式流程介绍

一、整体流程介绍 二、固件介绍 固件视频演示地址&#xff1a; ESP8266-配网&热点设置说明_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1hq4y127dN/?spm_id_from333.999.0.0

在屏蔽任何FRP环境下从零开始搭建安全的FRP内网穿透服务

背景 本人目前在境外某大学读博&#xff0c;校园网屏蔽了所有内网穿透的工具的数据包和IP访问&#xff0c;为了实现在家也能远程访问服务器&#xff0c;就不得不先开个学校VPN&#xff0c;再登陆。我们实验室还需要访问另一个大学的服务器&#xff0c;每次我都要去找另一个大学…

python从入门到精通(十六):python爬虫的BeautifulSoup4

python爬虫的BeautifulSoup4 BeautifulSoup4导入模块解析文件创建对象python解析器beautifulsoup对象的种类Tag获取整个标签获取标签里的属性和属性值Navigablestring 获取标签里的内容BeautifulSoup获取整个文档Comment输出的内容不包含注释符号BeautifulSoup文档遍历Beautifu…

电子电器架构 —— 区域控制器是未来架构的正解吗?

电子电器架构 —— 区域控制器是未来架构的正解吗? 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶…

IDEA生成可执行jar包

1. 进入需要打包的项目&#xff0c;选择 最上方菜单栏的 File → Project Structure 2. 选择 左侧菜单栏 Artifacts → 加号 → JAR → from modules with dependencies 3. 选择入口类 Main Class&#xff08;点击文件夹图标可以快速选择&#xff09;&#xff0c;点击 OK&#…

CSP-202012-2-期末预测之最佳阈值

CSP-202012-2-期末预测之最佳阈值 【70分思路】 本题的难点还是时间复杂度&#xff0c;暴力枚举会导致时间超限。对于每一个可能的阈值theta&#xff0c;代码都重新计算了整个predict数组&#xff0c;统计预测正确的数目&#xff0c;因为有两个嵌套的循环&#xff0c;使得时间…

Redis(02)——事务管理

事务概念 Redis事务的本质是一组命令的集合。事务支持一次执行多个命令&#xff0c;一个事务中所有命令都会被序列化&#xff0c;在事务执行过程中&#xff0c;会按照顺序串行化执行队列中的命令&#xff0c;其他客户端提交的命令请求不会插入到事务执行命令序列中 Redis事务…

图书商城系统

文章目录 图书商城系统一、项目演示二、项目介绍三、系统部分功能截图四、部分代码展示五、底部获取项目&#xff08;9.9&#xffe5;带走&#xff09; 图书商城系统 一、项目演示 网上书城 二、项目介绍 基于SSM的图书商城网站 运行环境:idea或eclipse 数据库:mysql 开发语…