[LeetCode] 6.N字形变换

一、题目描述

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N
A P L S I I G
Y   I   R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

示例 1:

输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"

示例 2:

输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P     I    N
A   L S  I G
Y A   H R
P     I

示例 3:

输入:s = "A", numRows = 1
输出:"A"

提示:

  • 1 <= s.length <= 1000
  • s 由英文字母(小写和大写)、',''.' 组成
  • 1 <= numRows <= 1000

二、题解

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

设 n 为字符串 s 的长度, r = n u m R o w s r=numRows r=numRows。对于 r = 1 r=1 r=1(只有一行)或者 r ≥ n r≥n rn(只有一列)的情况,答案与 s 相同,我们可以直接返回 s。对于其余情况,考虑创建一个二维矩阵,然后在矩阵上按 Z 字形填写字符串 s,最后逐行扫描矩阵中的非空字符,组成答案。

根据题意,当我们在矩阵上填写字符时,会向下填写 r 个字符,然后向右上继续填写 r − 2 r−2 r2 个字符,最后回到第一行,因此 Z 字形变换的周期 t = r + r − 2 = 2 r − 2 t=r+r−2=2r−2 t=r+r2=2r2,每个周期会占用矩阵上的 1 + r − 2 = r − 1 1+r−2=r−1 1+r2=r1 列。

因此我们有 ⌈ n t ⌉ \lceil \frac nt \rceil tn 个周期(最后一个周期视作完整周期),乘上每个周期的列数,得到矩阵的列数 c = ⌈ n t ⌉ ⋅ ( r − 1 ) c= \lceil \frac nt \rceil·(r-1) c=tn(r1)

创建一个 r r r c c c 列的矩阵,然后遍历字符串 s s s 并按 Z 字形填写。具体来说,设当前填写的位置为 ( x , y ) (x,y) (x,y),即矩阵的 x x x y y y 列。初始 ( x , y ) = ( 0 , 0 ) (x,y)=(0,0) (x,y)=(0,0),即矩阵左上角。若当前字符下标 i i i 满足 i ⋅ m o d t < r − 1 i· mod t<r−1 imodt<r1,则向下移动,否则向右上移动。

填写完成后,逐行扫描矩阵中的非空字符,组成答案。

Python
 def convert(self, s: str, numRows: int) -> str:n, r = len(s), numRowsif r == 1 or r >= n:return st = r * 2 - 2c = (n + t - 1) // t * (r - 1)mat = [[''] * c for _ in range(r)]x, y = 0, 0for i, ch in enumerate(s):mat[x][y] = chif i % t < r - 1:x += 1  # 向下移动else:x -= 1y += 1  # 向右上移动return ''.join(ch for row in mat for ch in row if ch)
C++
string convert(string s, int numRows) 
{int n = s.length(), r = numRows;if (r == 1 || r >= n) {return s;}int t = r * 2 - 2;int c = (n + t - 1) / t * (r - 1);vector<string> mat(r, string(c, 0));for (int i = 0, x = 0, y = 0; i < n; ++i) {mat[x][y] = s[i];if (i % t < r - 1) {++x; // 向下移动} else {--x;++y; // 向右上移动}}string ans;for (auto &row : mat) {for (char ch : row) {if (ch) {ans += ch;}}}return ans;
}
复杂度分析
  • 时间复杂度: O ( r ⋅ n ) O(r⋅n) O(rn),其中 r = n u m R o w s r=numRows r=numRows,n 为字符串 s 的长度。时间主要消耗在矩阵的创建和遍历上,矩阵的行数为 r,列数可以视为 O ( n ) O(n) O(n)
  • 空间复杂度: O ( r ⋅ n ) O(r⋅n) O(rn)。矩阵需要 O ( r ⋅ n ) O(r⋅n) O(rn) 的空间。

2.2 方法二:压缩矩阵空间

方法一中的矩阵有大量的空间没有被使用,能否优化呢?

注意到每次往矩阵的某一行添加字符时,都会添加到该行上一个字符的右侧,且最后组成答案时只会用到每行的非空字符。因此我们可以将矩阵的每行初始化为一个空列表,每次向某一行添加字符时,添加到该行的列表末尾即可。

Python
 def convert(self, s: str, numRows: int) -> str:r = numRowsif r == 1 or r >= len(s):return smat = [[] for _ in range(r)]t, x = r * 2 - 2, 0for i, ch in enumerate(s):mat[x].append(ch)x += 1 if i % t < r - 1 else -1return ''.join(chain(*mat))
C++
string convert(string s, int numRows) 
{int n = s.length(), r = numRows;if (r == 1 || r >= n) {return s;}vector<string> mat(r);for (int i = 0, x = 0, t = r * 2 - 2; i < n; ++i) {mat[x] += s[i];i % t < r - 1 ? ++x : --x;}string ans;for (auto &row : mat) {ans += row;}return ans;
}
复杂度分析
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n),压缩后的矩阵需要 O ( n ) O(n) O(n) 的空间。。

2.3 方法三: 直接构造

我们来研究方法一中矩阵的每个非空字符会对应到 s 的哪个下标(记作 i d x idx idx),从而直接构造出答案。

由于 Z 字形变换的周期为 t = 2 r − 2 t=2r−2 t=2r2,因此对于矩阵第一行的非空字符,其对应的 i d x idx idx 均为 t t t 的倍数,即 i d x ≡ 0 ( m o d t ) idx≡0(modt) idx0(modt);同理,对于矩阵最后一行的非空字符,应满足 i d x ≡ r − 1 ( m o d t ) idx≡r−1(modt) idxr1(modt)

对于矩阵的其余行(行号设为 i i i),每个周期内有两个字符,第一个字符满足 i d x ≡ i ( m o d t ) idx≡i(modt) idxi(modt),第二个字符满足 i d x ≡ t − i ( m o d t ) idx≡t−i(modt) idxti(modt)

Python
 def convert(self, s: str, numRows: int) -> str:n, r = len(s), numRowsif r == 1 or r >= n:return st = r * 2 - 2ans = []for i in range(r):  # 枚举矩阵的行for j in range(0, n - i, t):  # 枚举每个周期的起始下标ans.append(s[j + i])  # 当前周期的第一个字符if 0 < i < r - 1 and j + t - i < n:ans.append(s[j + t - i])  # 当前周期的第二个字符return ''.join(ans)
C++
string convert(string s, int numRows) 
{int n = s.length(), r = numRows;if (r == 1 || r >= n) {return s;}string ans;int 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;
}
复杂度分析
  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 为字符串 s s s 的长度。 s s s 中的每个字符仅会被访问一次,因此时间复杂度为 O ( n ) O(n) O(n)

  • 空间复杂度: O ( 1 ) O(1) O(1)。返回值不计入空间复杂度。

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

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

相关文章

每天一点python——day66

#每天一点Python——66 #字符串的分隔 #如图&#xff1a; #方法①split()从左开始分隔&#xff0c;默认空格为分割字符&#xff0c;返回值是一个列表 shello world jisuanji#首先创建一个字符串 list1s.split() print(list1)#输出结果是&#xff1a;[hello, world, jisuanji]注…

Git的原理与使用(一)

目录 Git初始 Git安装 Git基本操作 创建git本地仓库 配置git 工作区,暂存区,版本库 添加文件,提交文件 查看.git文件 修改文件 版本回退 小结 Git初始 git是一个非常强大的版本控制工具.可以快速的将我们的文档和代码等进行版本管理. 下面这个实例看理解下为什么需…

Java 简单实现一个 UDP 回显服务器

文章目录 UDP 服务端UDP 客户端实现效果UDP 服务端(实现字典功能)总结 UDP 服务端 package network;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException;public class UdpEchoServer {private Da…

【开源】基于Vue.js的大学兼职教师管理系统的设计和实现

目录 一、摘要1.1 项目介绍1.2 项目详细录屏 二、研究内容三、界面展示3.1 登录注册3.2 学生教师管理3.3 课程管理模块3.4 授课管理模块3.5 课程考勤模块3.6 课程评价模块3.7 课程成绩模块3.8 可视化图表 四、免责说明 一、摘要 1.1 项目介绍 大学兼职教师管理系统&#xff0…

Oracle中分区原理

在Oracle数据库中&#xff0c;分区是一种将表或索引数据逻辑上划分为多个部分的技术。每个分区 (Partition) 都像一个独立的小表&#xff0c;并可以单独进行管理和维护。通过使用分区&#xff0c;可以优化查询性能、提高数据加载和删除操作的效率&#xff0c;并提供更好的数据管…

AI:84-基于卷积神经网络的文化遗产保护与修复

🚀 本文选自专栏:人工智能领域200例教程专栏 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的代码,详细讲解供大家学习,希望可以帮到大家。欢迎订阅支持,正在不断更新中,…

Java13新增特性

前言 前面的文章&#xff0c;我们对Java9、Java10、Java11、Java12 的特性进行了介绍&#xff0c;对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 今天我们来一起看一下Java13这个版本的一些重要信息 版本介绍 Java 13 是在 2019 年 9 月 17 日…

Technology Strategy Patterns 学习笔记9 - bringing it all together

1 Patterns Map 2 Creating the Strategy 2.1 Ansoff Growth Matrix 和owth-share Matrix 区别参见https://fourweekmba.com/bcg-matrix-vs-ansoff-matrix/ 3 Communicating

Docker进阶——再次认识docker的概念 Docker的结构 Docker镜像结构 镜像的构建方式

前言 在微服务大量应用的互联网时代&#xff0c;经常能看到docker的身影。作为docker的爱好者&#xff08;在服务器安装MySQL&#xff0c;Redis。。。我用的都是docker&#xff09;&#xff0c;我也会持续深入学习和认识docker。 本篇博客再次介绍docker的基本概念&#xff0…

FPGA UDP RGMII 千兆以太网(3)ODDR

1 xilinx原语 在 7 系列 FPGA 中实现 RGMII 接口需要借助 5 种原语,分别是:IDDR、ODDR、IDELAYE2、ODELAYE2(A7 中没有)、IDELAYCTRL。其中,IDDR和ODDR分别是输入和输出的双边沿寄存器,位于IOB中。IDELAYE2和ODELAYE2,分别用于控制 IO 口输入和输出延时。同时,IDELAYE2 …

R系组播调优方案

修改/etc/sysctl.conf添加如下内容&#xff1a; Vim /etc/sysctl.con net.ipv4.ip_forward1 net.ipv4.ip_nonlocal_bind1 net.ipv4.conf.all.rp_filter0 net.ipv4.conf.default.rp_filter0 net.bridge.bridge-nf-call-arptables 0 net.bridge.bridge-nf-call-ip6tables 0 …

深度学习之基于Pytorch框架的MNIST手写数字识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 MNIST是一个手写数字识别的数据集&#xff0c;是深度学习中最常用的数据集之一。基于Pytorch框架的MNIST手写数字识…

如何生成安卓证书?

1、Android平台签名证书(.keystore)生成指南&#xff1a; Android平台签名证书(.keystore)生成指南 - DCloud问答 2、安装JRE环境&#xff08;推荐使用JRE8环境&#xff0c;如已有可跳过&#xff09; Download the Latest Java LTS Free配置环境变量 3、powerShell命令&#…

Vue Router active-class 属性

active-class 是 vue-router 模块的 router-link 组件的属性&#xff0c;当 router-link 标签被点击时将会应用这个样式。 单独在 router-link 标签上使用 active-class 属性 <router-link to"/about" active-class"active">about</router-link…

腾讯云3年期轻量应用服务器优惠(薅羊毛教程)

腾讯云轻量应用服务器特价是有新用户限制的&#xff0c;所以阿腾云建议大家选择3年期轻量应用服务器&#xff0c;一劳永逸&#xff0c;免去续费困扰。腾讯云轻量应用服务器3年优惠可以选择2核2G4M和2核4G5M带宽&#xff0c;3年轻量2核2G4M服务器540元&#xff0c;2核4G5M轻量应…

Python实用技巧:将 Excel转为PDF

将Excel文件转换为PDF可以方便储存表格数据&#xff0c;此外在打印或共享文档时也能确保表格样式布局等在不同设备和操作系统上保持一致。今天给大家分享一个使用第三方Python库Spire.XLS for Python 实现Excel转PDF的简单方法。 实现步骤 首先&#xff0c;通过pip命令来安装依…

C#中在.NET 7.0控制台应用使用ADO.NET的方法

目录 一、新建.NET Framwork类、通过ADO.NET访问数据库并生成库 1.操作流程 2.库源码 3.生成库 二、再建 .NET 7.0控制台应用、依赖像引用库 1. 操作流程 2.program.cs源码 3.在program.cs中查看类Class1定义 作者在上一篇文章中曾说过.NET 7.0框架下不支持ADO…

AWS云服务器EC2实例进行操作系统迁移

AWS云服务器EC2实例进行操作系统迁移 文章目录 AWS云服务器EC2实例进行操作系统迁移1. 亚马逊EC2云服务器简介1.2 亚马逊EC2云务器与弹性云服务器区别 2. 亚马逊EC2云服务器配置流程2.1 亚马逊EC2云服务器实例配置2.1.1 EC2实例购买教程2.1.1 EC2实例初始化配置2.1.2 远程登录E…

Python基础入门例程51-NP51 列表的最大与最小(循环语句)

最近的博文&#xff1a; Python基础入门例程50-NP50 程序员节&#xff08;循环语句&#xff09;-CSDN博客 Python基础入门例程49-NP49 字符列表的长度-CSDN博客 Python基础入门例程48-NP48 验证登录名与密码&#xff08;条件语句&#xff09;-CSDN博客 目录 最近的博文&…

Postman —— post请求数据类型

1、Postman中post的数据类型 post中有以下数据类型 1、form-data 2、x-www-form-urlencoded 3、raw 4、binary 2、Postman请求不同的post数据类型 from-data multipart/form-data&#xff0c;它将表单的数据组织成Key-Value形式&#xff0c;也可以上传文件&#xff0c;当…