6. Z 字形变换 - 力扣(LeetCode)
文章起笔:2021年10月26日15:55:21
问题描述及示例
将一个给定字符串 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zigzag-conversion
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的题解
这道题的思路还是比较直接的,第一眼看到觉得是不是要用二维数组来存储字符,但是仔细一想,如果 s
的长度较大时,二维数组中就会有大量的空元素,这显然是不大合理的,虽然觉得可行,但是我还是及时转变了思路。把 Z 字形的字符分别标上其在 s
中下标后,我很快发现了规律。
最上面一行和最下面一行的下标值都是 numRows - 1
的倍数。于是我就想着把下标和遍历顺序挂上钩。可以发现,在生成 Z 字形的图案时,填充的方向都是先往下再往上,一直如此循环直至 s
中的字符均被遍历。于是我就想到用一个 isDown
标志量来标识当前应该往下走还是应该往上走。而每次变换方向时,都是在首行或是末行,所以只要在这两个特殊的地方做方向的判断就可以了。
于是乎,大概思路就出来了:
遍历 s
,并事先创建一个二维数组 lines
,该二维数组用于存储遍历的结果,其第一维的长度就是 numRows
,而第二维在开始时就是一个空数组(每个空数组都用来存储对应 Z 字符中对应行的字符)。在遍历的同时,根据当前遍历字符的下标 i
先判断一下当前是往下的还是往上的,然后再将当前字符放入合适的行。
大致图示如下:
详解请看下方注释:
/**
* @param {string} s
* @param {number} numRows
* @return {string}
*/
var convert = function(s, numRows) {
// 如果设置行数为1,那么Z形化后的逐行遍历结果和原字符一样,直接返回s即可
// 如果这里不做判断,就会影响到后面计算remaining
if (numRows === 1) {
return s;
}
// lines用于存储Z字形的逐行遍历结果,它是一个二维数组,初始时只有对应行数的若干个空数组
let lines = Array.from({length: numRows}).map(
() => []
);
// isDown是一个标志量,用来判断当前是应该往上走还是该往下走,这是一个关键点
let isDown = false;
// position用于标识当前遍历字符应该lines中的哪个数组
let position = 0;
// remaining用来存储当前字符在s中的下标对 numRows 取余的结果,
// 用于判断当前是否该转向,也用于确定position的值,这也是一个关键变量
let remaining = 0;
// 开始遍历s字符串
for(let i = 0; i < s.length; i++) {
remaining = i % (numRows - 1);
// 如果remaining不为0,则说明当前字符不在Z字形图案的首行或尾行,也就不需要变换方向
// 保持原来的值就可以了,否则的话就取原来值的反值
isDown = remaining ? isDown : !isDown;
// 根据isDown来判断当前的方向,然后结合remaining余数来确定该将当前字符放到处于哪一行
// 注意方向不同的话,其确定行数的方式也不一样,从上往下的话就直接从lines的头部开始计算
// (取remaining即可),从下往上的话,就要注意从lines的尾部开始计算了
position = isDown ? remaining: numRows - remaining - 1;
// 将当前字符放到对于的行里
lines[position].push(s[i]);
}
// 注意遍历完成后,lines中存储的是各行的结果,需要将他们按序合并成一行
lines = lines.reduce((acc, cur) => acc.concat(cur));
// 最后将lines中单个字符合并成一个字符串
return lines.join('');
};
提交记录
执行结果:通过
1157 / 1157 个通过测试用例
执行用时:112 ms, 在所有 JavaScript 提交中击败了31.86%的用户
内存消耗:44.5 MB, 在所有 JavaScript 提交中击败了23.67%的用户
时间:2021/10/26 16:16
官方题解
更新:2021年7月29日18:43:21
因为我考虑到著作权归属问题,所以【官方题解】部分我不再粘贴具体的代码了,可到下方的链接中查看。
更新:2021年10月26日16:17:46
【更新结束】
有关参考
更新:2021年10月26日16:21:03
参考:Array.prototype.reduce() - JavaScript | MDN