将一个给定字符串 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 <= 1000s由英文字母(小写和大写)、','和'.'组成1 <= numRows <= 1000
实现思路:
一开始以为还要按照命令行输出的方式去做输出,观察过后实际上就是将字符串分成给定的 numRows行数,比如给定的numRows是3,那么就将字符串分为3个数组,最后再将数组依次拼接成一个字符串返回就好了。我们以示例1为例,经过观察我们发现了这样的规律:
| 对应字母 | 下标 | 行数 | 应存放的数组下标 |
|---|---|---|---|
| P | 0 | 1 | 0 |
| A | 1 | 2 | 1 |
| Y | 2 | 3 | 2 |
| P | 3 | 2 | 1 |
| A | 4 | 1 | 0 |
| L | 5 | 2 | 1 |
| I | 6 | 3 | 2 |
| S | 7 | 2 | 1 |
| H | 8 | 1 | 0 |
| I | 9 | 2 | 1 |
| R | 10 | 3 | 2 |
| I | 11 | 2 | 1 |
| N | 12 | 1 | 0 |
| G | 13 | 2 | 1 |
每次到达指定的最大行数之后行数开始减少,等到到达第一行后又开始增加,循环往复,应存放的下标也是同样的规律,并且应存放下标比行数少1,这个规律的周期是2n,利用这一点我们就可以开始编写代码了:
/**
* @param {string} s
* @param {number} numRows
* @return {string}
*/
const convert = function (s, numRows) {
// 定义应存放的数组下标
let i = 0;
// 定义周期,由于是2n,因此我们只需要判断周期的奇偶
let even = true;
// 定义存放字符串的数组
let cs = [];
for (let w of s) {
// 判断当前数组下标是否存在字符串,不存在则创建一个
if (cs[i] === undefined) {
cs.push('');
}
// 将字符追加到对应字符串
cs[i] += w;
// 判断当前字符串属于哪个周期,应存放数组下标是增加还是减少
even ? i++ : i--;
if (i === numRows - 1) {
even = false;
}
if (i === 0) {
even = true;
}
}
return cs.map(s => s).join('');
};