Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述:
将一个给定字符串 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
二、题解:
方法一 纵向数组法
- 原理。根据题意遍历字符串纵向排列出结果数组,再纵向遍历得出字符串即可。
- 思路。
- 遍历字符串
- 对每一个纵向进行生成数组
- 尾指针为0时,直接放入当前字符
- 尾指不针为0时,将当前字符替换数组序号为尾指针的那个,且尾指针--,跳出当前循环
- 每遍历numRows一次,尾指针重新赋值
- 在纵向遍历求出字符串即可
代码:
var convert = function(s, numRows) {
let res = ''
let arr = []
let lastLenth = 0
let index = 0
// 先遍历请求调整后的arr数组
while(index < s.length){
let newArr = new Array(numRows).fill('')
for(let i = 0 ;i<numRows;i++){
let item = s[index]?s[index]:''
index++
if(lastLenth === 0){
newArr[i] = item
}else {
// 非正规情况 尾指针减一请跳出当前循环
newArr[lastLenth] = item
lastLenth--
break
}
// 如果遍历完一次 对尾指针重赋值
if(i === numRows-1){
lastLenth = numRows>1?numRows-2:numRows-1
}
}
arr.push(newArr)
}
// 再纵向遍历求出字符串
for(let i = 0 ;i<numRows;i++){
for(let item of arr){
res+= item[i]?item[i]:''
}
}
return res
};
方法二 横向数组法
- 原理。根据题意遍历字符串横向排列出结果数组,再纵向遍历得出字符串即可。
- 思路。
- 遍历字符串
- 对每一个横向进行生成数组
- 尾指针为0时,resArr[i][count]放入当前字符
- 尾指不针为0时,resArr[lastLenth][count],且尾指针--,count++,跳出当前循环
- 每遍历numRows一次,尾指针重新赋值,count++
- 在纵向遍历求出字符串即可
代码:
var convert = function(s, numRows) {
let res = ''
let lastLenth = 0
let index = 0
let resArr = new Array(numRows).fill(0).map(item => [])
let count = 0
while(index < s.length){
for(let i = 0 ;i<numRows;i++){
let item = s[index]?s[index]:''
index++
if(lastLenth === 0){
resArr[i][count] = item
}else {
resArr[lastLenth][count] = item
lastLenth--
count++
break
}
if(i === numRows-1){
lastLenth = numRows>1?numRows-2:numRows-1
count++
}
}
}
for(let i = 0 ;i<resArr.length;i++){
res+= resArr[i].join('')
}
return res
};
二维数组的方式感觉略微慢了点,想到直接使用字符串替换第二维呢?
优化后代码:
var convert = function(s, numRows) {
if(numRows === 1) return s
let lastLenth = 0
let index = 0
let resArr = new Array(numRows).fill('')
while(index < s.length){
for(let i = 0 ;i<numRows;i++){
let item = s[index]?s[index]:''
index++
// 这里不是赋值,而是+=
if(lastLenth === 0){
resArr[i] += item
}else {
resArr[lastLenth]+= item
lastLenth--
break
}
if(i === numRows-1){
lastLenth = numRows-2
}
}
}
return resArr.join('')
};
方案比较
- 纵向数组法 时间复杂度 O(n2)?。
- 横向数组法 时间复杂度 O(n)。
三、总结
- 此题可以纵向数组法和横向数组法两种方案
- 纵向数组法主要是根据题意遍历字符串纵向排列出结果数组,再纵向遍历得出字符串即可。
- 横向数组法主要是根据题意遍历字符串横向排列出结果数组,再纵向遍历得出字符串即可。
文中如有错误,欢迎在评论区指正