算法,从承认自己是一个菜鸟开始!
本文是《算法-从菜鸟开始》系列文章的第7篇,欢迎收藏
、留言
、点赞
。
话不多说,让我们继续我们的算法之旅。
一、LeetCode 6. Z 字形变换
题目介绍:
将一个给定字符串 s
根据给定的行数 numRows
,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:
P A H NA P L S I I GY I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例:
输入: s = "PAYPALISHIRING", numRows = 3输出: "PAHNAPLSIIGYIR"
二、解题分析
这道算法题是非常有意思的,因为大多数的同学在第一次看到的时候根本就弄不明白,这个到底是在干啥。
到底是弄啥类?!
分析这道题时有一个诀窍,就是要把这个题目介绍中的Case
当成古代的武林秘籍
看,不同于现在文字横写的方式,古代武林秘籍是采用垂直竖
写的方式。
如果换个视角,采用竖
着,一列一列来来看题目,表现为:
- 从字符串
s
中取出一个放入当前行,再次取出一个放入下一行,重复这个行为; - 直到
numRows - 1
行,放置完成后; - 接下来该调整方向,往上一行放一个;
- 继续向上,直到第0行,调整方向,往下一行放一个。
同时要考虑特殊的情况,比如:
- 只需要1行时,直接返回字符串即可。
- 当
s.length <= numRows
即字符串长度小于行数时,也可以直接返回当前字符串。
基于以上的分析,我们来看代码的实现:
/**
* @param {string} s
* @param {number} numRows
* @return {string}
*/
var convert = function(s, numRows) {
// 特殊Case判定
if (s.length < numRows || numRows === 1) {
return s;
}
// 定义数组rows,对应存储每一行的字符串
const rows = []
// 使用变量i,表示rows的下标,代表了每一行
let i = 0;
// 使用变量j,表示字符串s的下标
let j = 0;
// 定义当前的填充字符的方向,-1表示向上,1表示向下
// 注意这里的初始值设置为-1,有特殊作用
let dir = -1;
// 遍历字符串,将每一个字符放入到对应的每一行中
while (j < s.length) {
// 要注意,对应的每一个i行,都是要拼接上最新的字符。
// 注意初rows[i]是否存在
rows[i] = rows[i] ? rows[i] += s[j] : s[j];
// 调整方向判定条件:第0行以及第numRows - 1行
if (i === 0 || i === numRows - 1) {
// 如果调整方向呢,当前值 *= -1即发生反向
dir *= -1;
}
// 当前行数发生变化
i += dir;
// 变量j发生变化,继续遍历子串s
j++;
}
// 将数组中的每行字符串再次进行拼接,并返回
return rows.join('');
};
三、总结
整体来看,这道算法题的问题主要集中于如何理解这个Z
字型展示的问题,分析展示的特点。得出展示的规律就好理解这个问题了。
当然解决这个问题的算法有很多种,比如去观察每一行字母的下标规律,出现的特点,也是可以计算的。欢迎大家多多动手尝试。
TIPS:
在JS中,我们经常使用 *= -1
的形式,来调整方向,尤其是在动画相关实现中。
算法-从菜鸟开始,而无止境。与君共勉!