题目描述:
将一个给定字符串 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);
题解:
class Solution:
def convert(self, s: str, numRows: int) -> str:
if numRows <= 1:
return s
res = ''
for i in range(numRows):
p = i
q = i
while p < len(s):
res += s[q]
if i != 0 and i != numRows - 1:
next_q = q + 2 * (numRows - 1 - i)
if next_q < len(s):
res += s[next_q]
p += 2 * (numRows - 1)
q = p
return res
思路:
-
特殊情况处理:
- 如果
numRows
小于等于 1,直接返回原始字符串s
,因为不需要进行ZigZag转换。
- 如果
-
初始化变量:
- 初始化一个空字符串
res
用于存储最终的结果。
- 初始化一个空字符串
-
循环遍历每一行:
- 使用
for
循环遍历每一行,行的索引从 0 到numRows - 1
。
- 使用
-
内部循环处理每一行的字符:
- 初始化两个变量
p
和q
为当前行的索引i
。 - 使用
while
循环,处理当前行的字符。- 将字符串
s
中索引为q
的字符添加到结果字符串res
中。 - 如果当前行不是第一行且不是最后一行(
i != 0
且i != numRows - 1
):- 计算中间字符的索引
next_q
,即q + 2 * (numRows - 1 - i)
。 - 检查
next_q
是否小于字符串的长度,如果是,则将该中间字符添加到结果字符串res
中。
- 计算中间字符的索引
- 将字符串
- 初始化两个变量
-
更新索引:
- 将
p
增加2 * (numRows - 1)
,以移动到下一个 "V" 形的起点。 - 更新
q
为新的p
的值。
- 将
-
返回结果:
- 最终结果字符串
res
就是按照 ZigZag 模式重新排列的字符串。
- 最终结果字符串
另一种解法:
评论区看到的利用flag,实在是牛。
class Solution:
def convert(self, s: str, numRows: int) -> str:
if numRows <= 1:
return s
res=["" for _ in range(numRows)]
i,flag=0,-1
for c in s:
res[i]+=c
if i==0 or i==numRows-1:
flag=-flag
i+=flag
return "".join(res)
思路:
每个按顺序遍历字符串 s
时,字符 c 在 N 字形中对应的 行索引 先从 s1增大至 sn,再从 sn减小至 s1…… 如此反复。因此解决方案为:模拟这个行索引的变化,在遍历 s
中把每个字符填到正确的行 res[i]
。