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

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

1
2
3
P   A   H   N
A P L S I I G
Y I R

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

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

1
string convert(string s, int numRows);

示例 1:

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

示例 2:

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

示例 3:

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

提示:

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

Z 字形变换其实是一个 非线性下标重排

假设原始字符串是 "PAYPALISHIRING",行数 numRows = 3

写出排列(带下标):

1
2
3
行0: 0     4     8     12     → P   A   H   N
行1: 1 3 5 7 9 11 13 → A P L S I I G
行2: 2 6 10 14 → Y I R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution:
def convert(self, s: str, numRows: int) -> str:
# 特殊情况:只有一行,直接返回原字符串
if numRows == 1 or numRows >= len(s):
return s

# 初始化每一行的字符串容器
rows = [''] * numRows
cur_row = 0 # 当前行
going_down = False # 是否向下移动

# 逐个字符放入对应的行
for c in s:
rows[cur_row] += c
# 到达第一行或最后一行时,改变方向
if cur_row == 0 or cur_row == numRows - 1:
going_down = not going_down
# 根据方向移动行索引
cur_row += 1 if going_down else -1

# 拼接所有行并返回
return ''.join(rows)