LeetCode 6. Z 字形变换(中)
Posted tonydandelion2014
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 6. Z 字形变换(中)相关的知识,希望对你有一定的参考价值。
6. Z 字形变换(中)
📖 题目
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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);
📝 示例
输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"
输入: s = "LEETCODEISHIRING", numRows = 4
输出: "LDREOEIIECIHNTSG"
解释:
L D R
E O E I I
E C I H N
T S G
🛰 考察知识点
指针、数组
💡 核心思想
通过从左向右迭代字符串,我们可以轻松地确定字符位于 Z 字形图案中的哪一行。
-
题目理解:
字符串 s 是以 Z字形为顺序存储的字符串,目标是按行打印。
设numRows
行字符串分别为 s 1 s_1 s1、 s 2 s_2 s2、 s 3 s_3 s3、… s n s_n sn 则容易发现:按顺序遍历字符串 s 时,每个字符 c 在 Z 字形中对应的 行索引 先从 s 1 s_1 s1增大至 s n s_n sn ,再从 s n s_n sn 减小至 s 1 s_1 s1,如此反复。重点是发现这个规律。
因此,解决方案为:模拟这个行索引的变化,在遍历 s 中把每个字符填到正确的行 res[i] 。类似于构造了一个指针确定应该将字符串放到那个位置。 -
算法流程: 按顺序遍历字符串 s;
-
res[i] += c
: 把每个字符 c 填入对应行 s i s_i si -
i += flag
: 更新当前字符 c 对应的行索引; -
flag = - flag
:在达到 Z字形转折点时,执行反向。
-
-
复杂度分析:
时间复杂度 O ( n ) O(n) O(n) :遍历一遍字符串 s;
空间复杂度 O ( n ) O(n) O(n) :各行字符串共占用 O ( n ) O(n) O(n) 额外空间。
参考连接 /
指针方法解决
💾 python版本
- 一个失败的例子,时间复杂度和空间复杂度都是 O ( n 2 ) O(n^2) O(n2),系统判定超出时间限制。
class Solution:
def convert(self, s: str, numRows: int) -> str:
if len(s) <= numRows:
return s
matrix = []
inter = numRows - 2
start = 0
end = numRows
all_in = True
while end<=len(s):
if all_in:
_segment = s[start:end]
# all_in之后 加进去
if len(_segment) < numRows:
_segment += "#" * (numRows-len(_segment))
matrix.append(list(_segment))
# 更新start end
start += numRows
if end == len(s):
break
if end+inter <= len(s):
end += inter
else:
end = len(s)
all_in = False
else:
_segment = s[start:end]
for j in range(len(_segment)):
# 创造一个str
tmp_str = "#"*(numRows-j-2) + _segment[j] + "#"*(j+1)
# 再转成list
matrix.append(list(tmp_str))
# 为all_in做准备
start = end
if end == len(s):
break
if end+numRows < len(s):
end += numRows
else:
end = len(s)
all_in = True
return_str = ""
for i in range(numRows):
for j in range(len(matrix)):
return_str += matrix[j][i]
return_str = return_str.replace("#", "")
return return_str
print("leet code accept!!!")
s = ["PAYPALISHIRING", "PAYPALISHIRING", "A"]
numRows = [3, 4, 2]
Answer = ["PAHNAPLSIIGYIR", "PINALSIGYAHRPI", "A"]
if __name__ == "__main__":
solution = Solution()
for i in range(len(s)):
print("-"*50)
result = solution.convert(s[i], numRows[i])
print(result==Answer[i])
- 数组方法,十分简洁且高效。
class Solution:
def convert(self, s: str, numRows: int) -> str:
if numRows < 2: return s # 只分成一行的话,直接返回就好 注意添加边界控制
res = ["" for _ in range(numRows)] # res十分巧妙 输入时刚好按照要输出的位置进行设置 最后直接调用str.join拼接res即可
i, flag = 0, -1 # i的作用是标记当前在那一行上添加 flag的作用是标记转移范围是向上还是向下并控制i的变化是增大还是变小
for c in s:
# 这三行代码的顺序不能变化
res[i] += c # 先将当前char安置在正确的行
if i == 0 or i == numRows - 1: flag = -flag # 再判断是第一行还是最后一行 决定是否要反转
i += flag # 更新要填入的目标行
tmp_res = ''
for i in res:
tmp_res += i
return tmp_res
# return "".join(res)
print("leet code accept!!!")
s = ["PAYPALISHIRING", "PAYPALISHIRING", "A"]
numRows = [3, 4, 2]
Answer = ["PAHNAPLSIIGYIR", "PINALSIGYAHRPI", "A"]
if __name__ == "__main__":
solution = Solution()
for i in range(len(s)):
print("-"*50)
result = solution.convert(s[i], numRows[i])
print(result==Answer[i])
时间复杂度和空间复杂度都是 O ( n ) O(n) O(n)
用时 | 内存 | 区别 |
---|---|---|
56 ms | 13.2 MB | return "".join(res) |
88 ms | 13 MB | return tmp_res |
说明,尽量不调用API做字符串处理,会更加耗时。
💻 有效语法糖
以上是关于LeetCode 6. Z 字形变换(中)的主要内容,如果未能解决你的问题,请参考以下文章