题目来源
题目描述
将一个给定字符串 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
题目解析
本题主要还是需要看图总结规律,然后进行逻辑模拟。
我总结规律如下:
通过上面图示,我们可以发现,起始 И 走势,可以分解为多组的直边(红色边)和斜边(绿色边)
因此,本题我们只要分析出直边和斜边的填充逻辑即可。
本题,我们可以定义一个长度 numRows 的字符串数组,对应于结果排列的各行。初始时,字符串数组元素都为空串。
无论直边的填充,还是斜边的填充,填充顺序都是固定的,即字符串 s 的遍历顺序
- 对于直边的填充,每次需要填充 numRows 个字符,填充是从 第0行 到 第numRows-1行 。
- 对于斜边的填充,每次需要填充 numRows - 2 个字符,填充是从第numRows-2行 到 第 1 行。
更多细节逻辑可以对照代码思考。
C源码实现
char* convert(char* s, int numRows) {
char rows[1001][1001] = {'\0'}; // rows[i] 用于记录结果排列的第 i 行字符串
int k = 0;
while (k < strlen(s)) { // 遍历字符串s的索引k
for (int i = 0; i < numRows && k < strlen(s); i++, k++) { // И的直边填充
char tmp[] = {s[k], '\0'};
strcat(rows[i], tmp);
}
for (int i = 0; i < numRows - 2 && k < strlen(s); i++, k++) { // И的斜边填充
char tmp[] = {s[k], '\0'};
strcat(rows[numRows - 2 - i], tmp);
}
}
char* res = (char*)calloc(strlen(s) + 1, sizeof(char));
for (int i = 0; i < numRows; i++) {
strcat(res, rows[i]);
}
return res;
}
C++源码实现
class Solution {
public:
string convert(string s, int numRows) {
vector<string> rows(numRows); // rows[i] 用于记录结果排列的第 i 行字符串
int k = 0; // 遍历字符串s的索引k
while (k < s.length()) {
for (int i = 0; i < numRows && k < s.length(); i++, k++) { // И的直边填充
rows[i] += s[k];
}
for (int i = 0; i < numRows - 2 && k < s.length(); i++, k++) { // И的斜边填充
rows[numRows - 2 - i] += s[k];
}
}
string res;
for (int i = 0; i < numRows; i++) {
res += rows[i];
}
return res;
}
};
Java源码实现
class Solution {
public String convert(String s, int numRows) {
StringBuilder[] sbs = new StringBuilder[numRows]; // sbs[i] 用于记录结果排列的第 i 行字符串
for (int i = 0; i < numRows; i++) {
sbs[i] = new StringBuilder();
}
int k = 0; // 遍历字符串s的索引k
while (k < s.length()) {
for (int i = 0; i < numRows && k < s.length(); i++, k++) { // И的直边填充
sbs[i].append(s.charAt(k));
}
for (int i = 0; i < numRows - 2 && k < s.length(); i++, k++) { // И的斜边填充
sbs[numRows - 2 - i].append(s.charAt(k));
}
}
return String.join("", sbs);
}
}
Python源码实现
class Solution(object):
def convert(self, s, numRows):
"""
:type s: str
:type numRows: int
:rtype: str
"""
rows = [""] * numRows # rows[i] 用于记录结果排列的第 i 行字符串
k = 0 # 遍历字符串s的索引k
while k < len(s):
for i in range(numRows): # И的直边填充
if k < len(s):
rows[i] += s[k]
k += 1
for i in range(numRows - 2): # И的斜边填充
if k < len(s):
rows[numRows - 2 - i] += s[k]
k += 1
return "".join(rows)
JavaScript源码实现
/**
* @param {string} s
* @param {number} numRows
* @return {string}
*/
var convert = function (s, numRows) {
const rows = new Array(numRows).fill(""); // rows[i] 用于记录结果排列的第 i 行字符串
let k = 0; // 遍历字符串s的索引k
while (k < s.length) {
for (let i = 0; i < numRows && k < s.length; i++, k++) { // И的直边填充
rows[i] += s[k];
}
for (let i = 0; i < numRows - 2 && k < s.length; i++, k++) { // И的斜边填充
rows[numRows - 2 - i] += s[k];
}
}
return rows.join("");
};