题目
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例
示例 1:
输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"
示例 2:
输入: s = "LEETCODEISHIRING", numRows = 4
输出: "LDREOEIIECIHNTSG"
解释:
L D R
E O E I I
E C I H N
T S G
解答
这道题目是用来找规律的。我们不用在乎字符串是什么样子,只需要把下标整理好就够了。如图所示,这里设输入为13个元素的字符串,行数为4,我们先把字符串的下标罗列一下:

我们可以观察到一些规律:
1.Z字形变换有重复结构,暂且称为“单元”,而且相邻单元相同位置的差值相同,记为node_length,例如10和4之间的差值、7和1之间的差值都是6;
2.每个单元包含一个垂直列和斜线列,垂直列从上到下连续递增;
3.第一行和最后一行在每个单元中只有一个元素,其他行在每个单元有两个,一个垂直列中的元素verticle_elem(绿色)和一个斜线列中的元素oblique_elem(红色),而且这两个元素下标存在关系:oblique_elem = verticle_elem + node_length - 2 * 当前行号,例如2和4分是同一个单元内的垂直列元素和斜线上元素,存在关系:4= 2 + 6 - 2 * 2 = 4,推导很简单;
我们逐行遍历,用row代表当前行号,从左到右逐个单元获得当前行当前单元的垂直列元素(绿色),如果不是第一行或最后一行,还要把当前行当前单元的斜线列元素(红色)加入到结果中。具体实现如下:
class Solution:
def convert(self, s, numRows):
"""
:type s: str
:type numRows: int
:rtype: str
"""
str_length = len(s) # 输入字符串长度
node_length = 2 * (numRows - 1) # 相邻单元相同位置的差值
result = "" # 结果变量
if str_length == 0 or numRows == 0 or numRows == 1:
return s
for row in range(numRows): # 逐行遍历
for verticle_elem in range(row, str_length, node_length): # 从左到右逐个单元遍历
result += s[verticle_elem] # 添加当前行中处在垂直列中的元素
oblique_elem = verticle_elem - 2 * row + node_length # 当前行中处在斜线上的元素下标
if row != 0 and row != numRows-1 and oblique_elem < str_length:
# 如果不是第一行和最后一行,在每个单元上一定存在斜线上元素inter_elem
result += s[oblique_elem] # 添加斜线上的元素
return result
如有疑问,欢迎评论区留言~