目录
- 1.题目
- 2.题解
- C# 解法一:利用二维矩阵模拟
- C# 解法二:压缩矩阵空间
- Python3 解法三:直接构造
1.题目
将一个给定字符串 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);
- 示例1:
输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"
- 示例 2:
输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P I N
A L S I G
Y A H R
P I
- 示例3:
输入:s = "A", numRows = 1
输出:"A"
- 提示:
- 1 <= s.length <= 1000
- s 由英文字母(小写和大写)、‘,’ 和 ‘.’ 组成
- 1 <= numRows <= 1000
2.题解
C# 解法一:利用二维矩阵模拟
public class Solution {
public string Convert(string s, int numRows) {
int n = s.Length, r = numRows;
if (r == 1 || r >= n) {
return s;
}
int t = r * 2 - 2;
int c = (n + t - 1) / t * (r - 1);
char[][] mat = new char[r][];
for (int i = 0; i < r; ++i) {
mat[i] = new char[c];
}
for (int i = 0, x = 0, y = 0; i < n; ++i) {
mat[x][y] = s[i];
if (i % t < r - 1) {
++x; // 向下移动
} else {
--x;
++y; // 向右上移动
}
}
StringBuilder ans = new StringBuilder();
foreach (char[] row in mat) {
foreach (char ch in row) {
if (ch != 0) {
ans.Append(ch);
}
}
}
return ans.ToString();
}
}
- 时间复杂度:O(r⋅n)
- 其中 r=numRows,n 为字符串 s 的长度。时间主要消耗在矩阵的创建和遍历上,矩阵的行数为 r,列数可以视为 O(n)
- 空间复杂度:O(r⋅n)
- 使矩阵需要 O(r⋅n) 的空间。
C# 解法二:压缩矩阵空间
- 方法一中的矩阵有大量的空间没有被使用,能否优化呢?
注意到每次往矩阵的某一行添加字符时,都会添加到该行上一个字符的右侧,且最后组成答案时只会用到每行的非空字符。因此我们可以将矩阵的每行初始化为一个空列表,每次向某一行添加字符时,添加到该行的列表末尾即可。
public class Solution {
public string Convert(string s, int numRows) {
int n = s.Length, r = numRows;
if (r == 1 || r >= n) {
return s;
}
StringBuilder[] mat = new StringBuilder[r];
for (int i = 0; i < r; ++i) {
mat[i] = new StringBuilder();
}
for (int i = 0, x = 0, t = r * 2 - 2; i < n; ++i) {
mat[x].Append(s[i]);
if (i % t < r - 1) {
++x;
} else {
--x;
}
}
StringBuilder ans = new StringBuilder();
foreach (StringBuilder row in mat) {
ans.Append(row);
}
return ans.ToString();
}
}
- 时间复杂度:O(n)。
- 空间复杂度:O(n)
- 压缩后的矩阵需要 O(n) 的空间。
Python3 解法三:直接构造
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)
- 其中 n 为字符串 s 的长度。s 中的每个字符仅会被访问一次,因此时间复杂度为 O(n)。
- 空间复杂度:O(1)
- 使返回值不计入空间复杂度。