Z 字形变换
题目描述:
将一个给定字符串 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);
示例:
输入:s = “PAYPALISHIRING”, numRows = 3
输出:“PAHNAPLSIIGYIR”
提示:
- 1 <= s.length <= 1000
- s 由英文字母(小写和大写)、’,’ 和 ‘.’ 组成
- 1 <= numRows <= 1000
解法
- 本题大致上有两个思路,第一个是遍历numRows,对于每一行,确定在这一行的所有元素的索引,然后填充完毕;第二个是遍历字符串,确定每个字符应该在哪一行,然后放置到相应行,最后再逐行打印。
- 第一种方法是比较复杂的,因为不同行的相邻元素之间有着不同的间隔,尽管整个数学关系是可以推导的,而且之前我也使用 Java 实现过,但真到面试了我觉得八成会大脑空白。
- 这里仅讨论第二种方法,它其实是对整个形状(走向)的模拟——开始的时候先从上往下放置字符,达到底部后再从下往上放置,达到顶部后又从上往下放置,循环往复,直到所有字符都完成排列。所以我们只需定义两个变量cur_row和direction:如果是从上往下走,direction = 1;如果是从下往上走,direction = -1;使用cur_row + direction来更新cur_row。
代码
class Solution:
def convert(self, s: str, numRows: int) -> str:
if len(s) == 1 or numRows == 1:
return s
res, cur_row, direction = [[] for _ in range(numRows)], 0, 1 # 先使用列表存储各元素,最后再转字符串(内存更优一些,java 是这样)
for ch in s:
res[cur_row].append(ch)
cur_row += direction
if cur_row == numRows - 1 or cur_row == 0: # 到达底部或顶部,变方向
direction *= -1
return "".join(reduce(lambda x, y: x + y, res)) # 各列表合并后,转为字符串
测试结果
执行用时:84 ms, 在所有 Python3 提交中击败了24.64% 的用户
内存消耗:15.2 MB, 在所有 Python3 提交中击败了20.15% 的用户
说明
算法题来源:力扣(LeetCode)