题目描述
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。
示例一
输入:s = “PAYPALISHIRING”, numRows = 3
输出:“PAHNAPLSIIGYIR”
示例二
输入:s = “PAYPALISHIRING”, numRows = 4
输出:“PINALSIGYAHRPI”
解释:
P I N
A L S I G
Y A H R
P I
解题思路
暴力解法。观察z字形排列的规律,每列可以看成一个键值对,即将每列的字符串作为字典的value,列数作为key,且给value添加空格,每个空格都占一个字符的位置,使得字典的value长度一致。而返回的结果字符串即字典的每一个值的对应位置的不为空格的字符。
代码实现
# python3
import math
class Solution:
def convert(self, s: str, numRows: int) -> str:
# 当输入字符串为1时,直接返回
if len(s)==1:
return s
# 添加的空格数与numRows的关系
add = numRows-2
x = 0
new_s=""
i = 0
# 遍历字符串的步长
step = add+numRows
if step == 0:
step = 1
for i in range(0,len(s),step):
# 按步长正常遍历时,需要添加空格的位置
new_s = new_s+s[i:i+numRows]+" "*add
print(f"new_s:{new_s}")
# 观察z字形的规律,每隔step个字符后会有numRows-2个字符需要加空格
while x<numRows-2:
new_s = new_s+s[i+numRows+x:i+numRows+x+1]+" "*add
x+=1
x=0
# 将新的字符串分割为numRows个子字符串,放入字典中
my_dict = {i:new_s[i*numRows:i*numRows+numRows] for i in range(math.ceil(len(new_s)/numRows))}
# 向上取整的目的是,当numRows大于输入字符串整除numRows的结果时,不会丢失零散的子字符串
# flag用于定位每个子字符串的单个字符位置,即z字形的第flag+1行
flag = 0
res=""
# 循环numRows次
u = 0
# strip用于去除字典中无意义的键值对
my_dict2 = {k: v for k, v in my_dict.items() if v.strip()}
while u<numRows:
for key in my_dict2.keys():
# 防止flag溢出
if flag>=len(my_dict2[key]):
break
if my_dict2[key][flag:flag+1]!=" ":
res += my_dict2[key][flag]
u+=1
flag+=1
return res
复杂度
时间复杂度:
O(n^2)
空间复杂度:
O(n)