一、题目描述
将一个给定字符串 s 根据给定的行数 numRows ,以 从上往下、从左到右 进行 Z 字形排列。
例如输入字符串为:
PAYPALISHIRING
当 numRows = 3 时,排列如下:
P A H N
A P L S I I G
Y I R
然后按 逐行读取 的顺序输出:
PAHNAPLSIIGYIR
示例:
示例 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
二、解题思路
Z 字形的核心规律是:
字符在 行之间上下移动。
例如 numRows = 4 时,行变化如下:
0 → 1 → 2 → 3 → 2 → 1 → 0 → 1 ...
也就是说:
-
到 第一行 时开始 向下
-
到 最后一行 时开始 向上
因此我们只需要:
-
创建
numRows个字符串(或字符数组) -
按照 上下移动规则 把字符加入对应行
-
最后 按行拼接 即可
示意:
row0: P I N
row1: A L S I G
row2: Y A H R
row3: P I
最终结果:
row0 + row1 + row2 + row3
三、特殊情况
有一个非常重要的特殊情况:
numRows == 1
例如:
s = "ABC"
numRows = 1
Z 字形无法形成,直接返回原字符串即可。
四、C语言代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* convert(char* s, int numRows) {
if(numRows == 1) return strdup(s);
int len = strlen(s);
// 创建每一行
char **rows = (char**)malloc(sizeof(char*) * numRows);
int *rowLen = (int*)calloc(numRows, sizeof(int));
for(int i = 0; i < numRows; i++){
rows[i] = (char*)malloc(sizeof(char) * (len + 1));
}
int curRow = 0;
int goingDown = 1;
for(int i = 0; i < len; i++){
rows[curRow][rowLen[curRow]++] = s[i];
if(curRow == 0)
goingDown = 1;
else if(curRow == numRows - 1)
goingDown = 0;
curRow += goingDown ? 1 : -1;
}
// 拼接结果
char *res = (char*)malloc(sizeof(char) * (len + 1));
int pos = 0;
for(int i = 0; i < numRows; i++){
for(int j = 0; j < rowLen[i]; j++){
res[pos++] = rows[i][j];
}
free(rows[i]);
}
res[pos] = '\0';
free(rows);
free(rowLen);
return res;
}
五、复杂度分析
时间复杂度
O(n)
每个字符只遍历一次。
空间复杂度
O(n)
需要额外空间存储每一行的字符。
六、思路总结
本题的关键在于理解 Z 字形的行变化规律:
向下 → 到底 → 向上 → 到顶 → 向下
即:
0 → 1 → 2 → ... → numRows-1 → numRows-2 → ... → 1 → 0
利用一个 方向变量 goingDown 控制移动即可。
解题步骤:
-
创建
numRows行 -
按 Z 字形顺序填充字符
-
最后按行拼接输出