写在前面
本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……
专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:
- Tag:介绍本题牵涉到的知识点、数据结构;
- 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
- 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
- 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
- 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。
Tag
【字符串】【二维矩阵模拟】【一次遍历】
题目来源
解题思路
方法一:二维矩阵模拟
一种朴素的解法是将字符串 s
按其形状填写到二维矩阵上,然后逐行遍历句还早呢中的非空字符,组成答案。
二维矩阵的行和列分别为多少?行数就是 r
,列数需要花点时间计算一下。
设 n
为字符串 s
的长度,r = numRows
。对于特殊情况,字符串只有一行(r = 1
)或者只有一列(r >= n
),直接返回 s
。
根据题意,当我们在矩阵上填写字符时,会向下(前文图片中竖的方向)填写 r
个字符,然后向右上(斜的方向)填写 r - 2
个字符,最后回到一行。于是可以清楚的知道 Z 字形变换的周期 t = r + r - 2 = 2r - 2
,每个周期会占据矩阵中的 1 + r - 2 = r - 1
列。
因此我们有 ⌈ n t ⌉ \lceil{\frac{n}{t}}\rceil ⌈tn⌉ 个周期,乘上每个周期的列数,于是可以得到矩阵的列数为 c = ⌈ n t ⌉ ⋅ ( r − 1 ) c = \lceil{\frac{n}{t}}\rceil \cdot (r-1) c=⌈tn⌉⋅(r−1)。
创建一个 r
行 c
列的矩阵,现在根据字符串的下标 i
来更新矩阵的 x
行 y
列。具体地初始化 (x, y) = (0, 0)
:
- 若
i % t < r - 1
,说明现在的字符处在 “竖” 阶段,接着向下移动; - 否则,说明现在的字符处在 “斜” 阶段,需要更新
--x, ++y
。
代码
class Solution {
public:
string convert(string s, int r) {
int n = s.size();
if (r == 1 || r >= n) {
return s;
}
int t = 2*r - 2; // 一个周期的字符数
int c = (n + t - 1) / t * (r - 1);
vector<string> mat(r, string(c, 0));
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;
}
}
string res;
for (auto& row : mat) {
for (char c : row) {
if (c) {
res += c;
}
}
}
return res;
}
};
复杂度分析
时间复杂度:
O
(
r
⋅
n
)
O(r \cdot n)
O(r⋅n),
r
=
n
u
m
R
o
w
s
r = numRows
r=numRows,
n
n
n 为字符串 s
的长度。
空间复杂度: O ( r ⋅ n ) O(r \cdot n) O(r⋅n)。
方法二:一次遍历
思路
注意到每次往矩阵的某一行添加字符时,都会添加到该行上一个字符的右侧,且最后组成答案时只会用到每行的非空字符。因此我们可以将矩阵的每行初始化为一个空列表,每次向某一行添加字符时,添加到该行的列表末尾即可。
并且维护一个 bool 变量表示现在下一次操作是更新下一行还是上一行的字符串,若为 true
更新下一行,否则更新上一行。
代码
class Solution {
public:
string convert(string s, int r) {
int n = s.size();
if (r == 1 || r >= n)
return s;
vector<string> rows(r);
bool goingDown = false;
int curRow = 0;
for (char c : s) {
rows[curRow] += c;
if (curRow == 0 || curRow == r - 1)
goingDown = !goingDown;
curRow += goingDown ? 1 : -1;
}
string ret;
for (string row : rows)
ret += row;
return ret;
}
};
复杂度分析
时间复杂度:
O
(
n
)
O(n)
O(n),
n
n
n 为字符串 s
的长度。
空间复杂度: O ( n ) O(n) O(n)。
写在最后
如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。
最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。