:中等
题目简介:
将一个给定字符串 s 根据给定的行数 numRows ,以进行 Z 字形排列。
比如输入字符串为 "ABCDEFGHIJKLMNO" 行数为 5 时,排列如下:
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:
结果为 AIBHJCGKODFLNEM
请你实现这个将字符串进行指定行数变换的函数:
示例 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 <= 1000s由英文字母(小写和大写)、','和'.'组成1 <= numRows <= 1000
思路
代码结果
这是简单版,详细的在下面
function convert(s: string, numRows: number): string {
const len = s.length;
if (numRows === 1 || len <= numRows) {
return s;
}
//周期, 如 numRows = 5,cycle就为8,表示每8个字符完成一个Z,
const cycle = 2 * numRows - 2;
const result: string[] = [];
for (let i = 0; i < numRows; i++) {
for (let j = 0; j < len - i; j += cycle) {
//获取该周期内,当前行的第一个字符
result.push(s[j + i]);
if (i > 0 && numRows - 1 > i && len > j + cycle - i) {
//获取该周期内,当前行的第二个字符
result.push(s[j + cycle - i]);
}
}
}
return result.join("");
}
convert("PAYPALISHIRING", 3);
图文详解回答
function convert(s: string, numRows: number): string {
const len = s.length;
// numRows === 1 只有一行,直接返回
// len <= numRows 只有一列,直接返回
if (numRows === 1 || len <= numRows) {
return s;
}
convert("ABCDEFGHIJKLMNO", 5)
: numRows === 1
: len <= numRows
字符串长度 小于 行长度的话,则一行最多只有一个字符,也就是只有一列
function convert(s: string, numRows: number): string {
//周期, 如 numRows = 5,cycle就为8,表示每8个字符完成一个Z,
const cycle = 2 * numRows - 2;
}
一个周期的字符数为,一列()➕ 斜着的部分()
= 行数 = numRows
= 行数 - 第一行 - 最后一行 = numRows - 1 - 1
= numRows + numRows - 1 - 1 = 2 * numRows -2
准备工作做完,这时候,要开始循环行数了
function convert(s: string, numRows: number): string {
//用于返回的结果
const result: string[] = [];
// 循环行数,获取每一行
for (let i = 0; i < numRows; i++) {
// 循环剩余字符
for (let j = 0; j < len - i; j += cycle) {
// s[j + i] : 获取当前周期内的第一列的值
result.push(s[j + i]);
}
}
}
第一个循环是获取每一行
第二个循环: 循环剩余字符
当第一层循环 i = 0时,第二层循环则要遍历所有字符,以获取 A、I
当第二层循环 i = 1时,第二层循环则要所有的字符(),以获取 B、H、J
当第三层循环 i = 2时,第二层循环则要所有的字符(),以获取 C、G、K、O
按照上面的步骤:
: 排除A、B等
: 这个解释如下
第二循环的第一轮次时,j=0,j 指向 A 的索引
第二循环的第二轮次时,j=8,j 指向 I 的索引
第二循环的第一轮次时,j=0, 指向 B 的索引
第二循环的第二轮次时,j=8, 指向 J 的索引
注意,第二循环的第二轮次时,直接 获取的是 J,而不是 H,因为 s[j + i],只能获取该周期内的第一个数,而 H属于第一周期的第二个数,需要下面这种方式获取
function convert(s: string, numRows: number): string {
const result: string[] = [];
for (let i = 0; i < numRows; i++) {
for (let j = 0; j < len - i; j += cycle) {
result.push(s[j + i]);
// 获取该周期的第二个数
if (i > 0 && numRows - 1 > i && len > j + cycle - i) {
//将该周期的第二列放入数组
result.push(s[j + cycle - i]);
}
}
}
}
可以看到,单个周期中的第一行()和 最后一行 (,是没有第二列的。
: 排除了第一行
: 排除了第一行
由于在第二层循环中, j的增长方式是 ,而cycle为一个完整周期的数量,看下面的图片。当第二个周期时, 获取的是到 的数量,而字符串中根本,所以要排除掉
: 排除单个周期不存在的第二列
之后,获取的数组变成字符串就可以了。