Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述:
- 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 示例 3:
输入:s = "A", numRows = 1 输出:"A"
提示:
1 <= s.length <= 1000 s 由英文字母(小写和大写)、',' 和 '.' 组成 1 <= numRows <= 1000
二、题目和思路分析:
这个题目我反反复复看三遍才看懂,竖形的Z,要先由上到下,再由下向上排,最后横着取。
题目是看懂了,但是做法想来想去是毫无思路啊!
再想想,规律肯定是有的,每一列的长度是numRows,在理想长度下,奇数列长度是numRows,偶数列的长度是numRows-2,奇数行是s[0],s[6],s[12],s[18],每一行的长度是s[(4-n)*n] ......
越想越乱,我还是把下标列出来试试,于是我打了半天字,终于把下标打出来了:
看着下标我又开始了分析:
第一行的下标规律是 (n+n-2) * (row-1), 第二行的下标规律是 ....
啊啊啊啊啊啊,为什么会有这种题!
我还在纸上列了一页纸来分析,好难!
大概是我的思路不对,虽然知道是有规律的,但是就这么看着找规律总是困难的,我还是换个想法吧。
如果顺着题目来列,把每一行当成一个数组,那么就需要三步:
声明numRows个空数组
按顺序往数组添加值
数组合并,转字符串
能不能根据这三步来实现呢?
能!
首先把numRows个空数组放到一个对象中,然后遍历字符串,判断正序or倒序,向对应数组内添加元素,最后遍历存放数组的对象,合并数组,转字符串即可。
为了避免出错,我每一行都写了注释,一遍通过,大功告成!
三、代码:
代码实现如下:
/**
* @param {string} s
* @param {number} numRows
* @return {string}
*/
var convert = function(s, numRows) {
// 声明numRows个空数组
// 按顺序往数组添加值
// 数组合并
let obj = {
arr1: []
}
let i = 1
while(i <= numRows){
obj['arr'+i] = []
i++
}
let j = 1 // 当前轮候到的数组
let sort = true // 正序
for(let i = 0; i < s.length; i++){
obj['arr'+j].push(s[i]) // 向当前轮候到的数组添加值
if(j == 1) sort = true // 当前操作的数组是第一个,则继续向下
if(j == numRows) sort = false // 当前操作的数组是最后一个,则向上操作
if(sort){ // 向下操作
if(++j>numRows) { // 如果向下操作时,下次轮候的数组超出最后一个数组外,则将轮候数组改为倒数第二个,且改为向上操作
j = j-2
sort = false
}
}else{ // 向上操作
if(--j<1){ // 如果向上操作时,下次轮候的数组超出第一个数组外,则将轮候的数组改为第二个,且改为向下操作
j = 1
sort = true
}
}
}
let arr = []
for(key in obj){
arr = arr.concat(obj[key])
}
return arr.join('')
};
四、总结:
这道题看起来比较奇怪,对就是奇怪,因为我一开始怎么也没想起来该怎么做才好,最开始的找规律做法翻来覆去也不对,最后才发现可以让代码顺着题目意思去跑,不必非要去想它的规律。
不过这种做法应该没有找规律来的简单快捷,能看出规律的大概都是些比较聪明的人吧!
加油吧!