Leetcode 0006. Zigzag Conversion
6. Zigzag Conversion
题目
The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
1 | P A H N |
And then read line by line: "PAHNAPLSIIGYIR"
Write the code that will take a string and make this conversion given a number of rows:
1 | string convert(string s, int numRows); |
Example 1:
1 | Input: s = "PAYPALISHIRING", numRows = 3 |
Example 2:
1 | Input: s = "PAYPALISHIRING", numRows = 4 |
Example 3:
1 | Input: s = "A", numRows = 1 |
Constraints:
1 <= s.length <= 1000sconsists of English letters (lower-case and upper-case),','and'.'.1 <= numRows <= 1000
解题思路
解法一:方向模拟法(推荐)
Z 字形的本质是一个"来回扫描"的过程:行号从 0 递增到 numRows - 1,然后递减回 0,再递增……如此循环。维护一个行游标 row 和方向步长 step(+1 向下,-1 向上),当游标到达顶部或底部时翻转方向。一趟遍历即可将每个字符分配到对应行,最后按行拼接。
以 s = "PAYPALISHIRING", numRows = 4 为例:
1 | s = P A Y P A L I S H I R I N G |
核心代码逻辑:
- 若
numRows == 1或numRows >= n,直接返回s(退化情况) - 初始化
numRows个空字符串,row = 0,step = 1 - 遍历每个字符:追加到当前行 → 移动行游标 → 到达边界时翻转方向
- 拼接所有行
时间复杂度 O(n),空间复杂度 O(n)(存储结果,不计输出则为 O(1) 额外空间)。
1 | class Solution { |
核心优化点解析
方向翻转的时机
先 row += step,再判断 row == 0 || row == numRows - 1。这样初始 row = 0, step = 1 时,第一次 row += step 使 row = 1,不会错误触发边界翻转。后续 row 在 0 和 numRows - 1 之间自然摆动。
退化情况处理
当 numRows == 1 时,step 会一直在 row == 0 时翻转(触顶又触底同时满足),导致 row 在 0 和 -1 之间震荡。因此必须在进入模拟前处理这个特殊情况。同理,numRows >= n 时每个字符独占一行,无 Z 字形可言,直接返回原串即可。
使用 vector<string> 而非二维数组
不需要真的构建 Z 字形的二维矩阵,用 numRows 个字符串收集字符即可。这避免了预先计算矩阵宽度,也省去了填充空格的开销。
解法二:直接索引法
Z 字形的排列是周期性的。设 cycle = 2 × numRows - 2(当 numRows > 1 时),每个周期包含一次"下降"(numRows 个字符)和一次"上升"(numRows - 2 个字符)。
以 numRows = 4 为例,cycle = 6:
1 | 周期0: P(0) 周期1: I(6) |
每行下标公式(k = 0, 1, 2, …,保证下标 < n):
- 首行 (
r = 0):k × cycle - 末行 (
r = numRows - 1):k × cycle + numRows - 1 - 中间行 (
0 < r < numRows - 1):每个周期有两个下标——k × cycle + r和k × cycle + cycle - r
时间复杂度 O(n),空间复杂度 O(1)(不计输出)。
1 | class Solution { |
两种解法对比
| 维度 | 方向模拟法 | 直接索引法 |
|---|---|---|
| 时间复杂度 | O(n) | O(n) |
| 空间复杂度 | O(n)(vector<string>) |
O(1)(不计输出) |
| 代码可读性 | ★★★★★ 极直观 | ★★★☆☆ 需理解周期公式 |
| 边界处理 | 仅需 numRows==1 特判 |
需分三种行类型处理 |
| 适用场景 | 面试、日常开发 | 追求极致内存的场景 |
推荐方向模拟法:代码逻辑与人对 Z 字形的直觉完全一致——"向下走到底,再向上走到顶",三句话讲清。直接索引法的周期公式虽然优雅,但面试中容易因下标计算失误写出 bug。

