文章目录
- 写在前面
- Tag
- 题目来源
- 解题思路
- 方法一:二维矩阵模拟
- 方法二:一次遍历
- 写在最后
写在前面
本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……
专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:
- Tag:介绍本题牵涉到的知识点、数据结构;
- 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
- 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
- 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
- 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。
Tag
【字符串】【二维矩阵模拟】【一次遍历】
题目来源
6. Z 字形变换
解题思路
方法一:二维矩阵模拟
一种朴素的解法是将字符串 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)。
写在最后
如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。
最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。