6. Z 字形变换
题目:
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
链接 https://leetcode.cn/problems/zigzag-conversion/
个人思路
- 观察示例可以发现,字符串s的每个字符将要摆放在的行的序列为0,1,2,3,2,1,0,1,2,3···,因此这就是一个0,1,2,3,2,1的循环,也就是0,1,2,···,numRows,numRows-1,···,1的循环。
- 我们先来构造这样一个循环:
a = [i for i in range(0,numRows)]
b = [j for j in range(numRows-2,0,-1)]
index = a + b
- 接下来计算s会在index中循环多少次:构造刚好能够容纳s长度的列表
# 计算列表长度
x = len(s) // len(index)
y = len(s) % len(index)
index = index * x + index[0:y]
- 接下来循环,把s中的每个字符放进以index元素为key的字典,最后返回即可
总的代码如下:
class Solution:
def convert(self, s: str, numRows: int) -> str:
# 先排除一行的情况,否则后面构造列表会报错
if numRows == 1:
return s
a = [i for i in range(0,numRows)]
b = [j for j in range(numRows-2,0,-1)]
index = a + b
# 计算列表长度
x = len(s) // len(index)
y = len(s) % len(index)
index = index * x + index[0:y]
# 储存结果中的每一行
haxi = {}
for i in range(len(s)):
haxi[index[i]] = haxi.get(index[i],'') + s[i]
ans = ''
for key in range(numRows):
ans = ans+haxi.get(key,'')
return ans
官方思路
- 利用二维矩阵模拟
(本来我也想到了用矩阵去做,但觉得挺麻烦的,然后感觉找规律能做出来,就用规律去做了)
class Solution:
def convert(self, s: str, numRows: int) -> str:
n, r = len(s), numRows
if r == 1 or r >= n:
return s
t = r * 2 - 2
c = (n + t - 1) // t * (r - 1)
mat = [[''] * c for _ in range(r)]
x, y = 0, 0
for i, ch in enumerate(s):
mat[x][y] = ch
if i % t < r - 1:
x += 1 # 向下移动
else:
x -= 1
y += 1 # 向右上移动
return ''.join(ch for row in mat for ch in row if ch)
该方法比较时间可空间复杂度较高
复杂度分析
时间复杂度:O(r⋅n),其中 }r=numRows,n为字符串 s的长度。时间主要消耗在矩阵的创建和遍历上,矩阵的行数为 rr,列数可以视为 O(n)。
空间复杂度:O(r⋅n)。矩阵需要O(r⋅n) 的空间。
-
压缩矩阵空间
上面方法中的矩阵有大量的空间没有被使用,能否优化呢?
注意到每次往矩阵的某一行添加字符时,都会添加到该行上一个字符的右侧,且最后组成答案时只会用到每行的非空字符。因此我们可以将矩阵的每行初始化为一个空列表,每次向某一行添加字符时,添加到该行的列表末尾即可。
class Solution:
def convert(self, s: str, numRows: int) -> str:
r = numRows
if r == 1 or r >= len(s):
return s
mat = [[] for _ in range(r)]
t, x = r * 2 - 2, 0
for i, ch in enumerate(s):
mat[x].append(ch)
x += 1 if i % t < r - 1 else -1
return ''.join(chain(*mat))
- 直接构造
和我做的思路一样
class Solution:
def convert(self, s: str, numRows: int) -> str:
n, r = len(s), numRows
if r == 1 or r >= n:
return s
t = r * 2 - 2
ans = []
for i in range(r): # 枚举矩阵的行
for j in range(0, n - i, t): # 枚举每个周期的起始下标
ans.append(s[j + i]) # 当前周期的第一个字符
if 0 < i < r - 1 and j + t - i < n:
ans.append(s[j + t - i]) # 当前周期的第二个字符
return ''.join(ans)
复杂度分析
时间复杂度:O(n),其中 nn 为字符串 s的长度。s中的每个字符仅会被访问一次,因此时间复杂度为 O(n)。
空间复杂度:O(1)。返回值不计入空间复杂度。
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/zigzag-conversion/solution/z-zi-xing-bian-huan-by-leetcode-solution-4n3u/
来源:力扣(LeetCode)
其他思路
本质上还是找规律,但代码中flag用的很妙
class Solution:
def convert(self, s: str, numRows: int) -> str:
if numRows < 2: 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)
作者:jyd
链接:https://leetcode.cn/problems/zigzag-conversion/solution/zzi-xing-bian-huan-by-jyd/
来源:力扣(LeetCode)