持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
Z字形变换
题目
6. Z 字形变换
将一个给定字符串 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
简单解法
事实就是能用数学直接解出的话,一定是比别的方法要快要省空间。但是往往会比较难以思考,考虑计算公式,边界问题等等。
所以我们先给出矩阵构造的方法,注意题目是z,但我们解决问题是N字形的,因此我们将N拆分为一行一行的数据,由此来构造二维矩阵,再将二维矩阵每一行依次拼成最后的结果。 (注意:我们可以压缩矩阵,因为我们最后只需要将一行一行的数据拼接就可以,因此每一行都只需要往后push就可以了,而不需要每行都新建s.length长度的数组)
function convert(s: string, numRows: number): string {
if (s.length <= numRows||numRows===1) return s;
const n = numRows;
let res = "";
let arr = new Array<Array<string>>(numRows);
const t = 2 * n - 2;
for (let i = 0; i < s.length; ++i) {
arr[i] = [];
}
let row = 0;
// row为行坐标
for (let i = 0; i < s.length; i++) {
arr[row].push(s[i]);
if (i % t < n - 1) {
// 当未走到拐点时row下移,否则上移
// n-i即是底行的坐标
row++;
} else {
row--;
}
}
console.table(arr);
arr.forEach((item) => {
item.forEach((item) => {
res += item;
});
});
return res;
}
console.log(convert("PAYPALISHIRING", 3)); //PAHNAPLSIIGYYIIRR
直接构造
由上,我们用数学公式直接拼接字符数组,还是一行一行的拼接,只不过我们将N的一个竖线和斜线组成一个周期,那么我们在每个周期没将属于当前遍历的行的数据拼接到字符数组后面就可以了
不要问我为什么用字符数组而不直接用res+="s",因为我还不太清楚js里到底是join(“”)快还是字符拼接快。但根据java课上学过的知识,+=的每次操作是比较耗费空间的,因此选用join。
// 直接计算
function convert(s: string, numRows: number): string {
if (s.length <= numRows) return s;
let res: string[] = [];
const t = 2 * numRows - 2;
// t就是一个周期的数据的数量
for (let i = 0; i < numRows; i++) {
// i可以理解为前面二维矩阵的行
for (let j = 0; j < s.length - i; j += t) {
res.push(s[j + i]); //这是每个周期的竖线的值
if (i > 0 && i < numRows - 1 && j + t - i < s.length) {
// 有斜线值的情况是在斜线区间内且不超过s的长度
res.push(s[j + t - i]);
// j加上一个周期减去i就是斜线位置
}
}
}
return res.join("");
}
总结
本次文章的难点在于直接构造的数学思想,在行的基础上将数据分为一个一个的周期,再依次将每个周期的数据拼接
结语
本次的文章到这里就结束啦!♥♥♥读者大大们认为写的不错的话点个赞再走哦 ♥♥♥
每天一个知识点,每天都在进步!♥♥