题目描述
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "LEETCODEISHIRING"
行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"
。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
- 输入:
s = "LEETCODEISHIRING", numRows = 3
- 输出:
"LCIRETOESIIGEDHN"
示例 2:
- 输入:
s = "LEETCODEISHIRING", numRows = 4
- 输出:
"LDREOEIIECIHNTSG"
解释:
L D R
E O E I I
E C I H N
T S G
解题思路
1、直接解法
在面试的时候,有时候第一时间想不到好的解法,可以先给出一个直接的解法(暴力解),本题最直接的做法就是根据给定的函数 numRows
,新建 numRows
个数组来遍历字符串进行保存,然后再将它们拼接起来即可。
需要注意的时,当字符个数小于给定的
numRows
时,只需要创建字符个数的数组就OK
该算法的时间复杂度为 O ( n ) O(n) O(n)
Java代码:
class Solution {
public String convert(String s, int numRows) {
//如果字符串为空,或长度小于等于1,或行数为1,直接返回
if(s == null || s.length() <= 1 || numRows == 1){
return s;
}
//求需要创建的数组个数
int nums = Math.min(numRows, s.length());
StringBuilder[] rows = new StringBuilder[nums];
for(int i = 0; i < nums; i++){
rows[i] = new StringBuilder();
}
boolean flag = false; //表示时向下移动还是向上移动
int curRow = 0; //当前遍历行数
for(int i = 0; i < s.length(); i++){
rows[curRow].append(s.charAt(i));
//第一行或者最后一行
if(curRow == 0 || curRow == numRows - 1){
flag = !flag;
}
curRow += flag ? 1 : -1;
}
//拼接起来
for(int i = 1; i < nums; i++){
rows[0].append(rows[i].toString());
}
return rows[0].toString();
}
}
2、解法二
其实本题每行相邻字符之前存在一定的规律,因此,只要总结出规律就OK了
- 第一行每个字符之间相差
2n-2
(这个差表示这两个字符在原字符串中相差几个字符) - 第二行每个字符之间相差
2n-4
和2
交替 - 第三行每个字符之间相差
2n-6
和4
交替 - … …
- 倒数第三行每个字符之间相差
4
和2n-6
交替 - 倒数第二行每个字符之间相差
2
和2n-4
交替 - 倒数第一行每个字符之间相差
2n-2
该算法的时间复杂度为 O ( n ) O(n) O(n)
Java代码:
class Solution {
public String convert(String s, int numRows) {
//如果字符串为空,或长度小于等于1,或行数为1,直接返回
if(s == null || s.length() <= 1 || numRows == 1){
return s;
}
int temp = 2 * numRows - 2;
StringBuilder str = new StringBuilder();
for(int i = 0; i < numRows; i++){
for(int j = i; j < s.length(); j += temp){
//上图红色框内,都相差2n-2
str.append(s.charAt(j));
//如果不是第一行和最后一行,交替
if(i != 0 && i != numRows - 1 && j + temp - 2 * i < s.length()){
str.append(s.charAt(j + temp - 2 * i));
}
}
}
return str.toString();
}
}
C++代码:
class Solution {
public:
string convert(string s, int nRows) {
if (nRows <= 1) return s;
string res = "";
int temp = 2 * nRows - 2;
for (int i = 0; i < nRows; i++) {
for (int j = i; j < s.size(); j += temp) {
res += s[j];
int tmp = j + temp - 2 * i;
if (i != 0 && i != nRows - 1 && tmp < s.size()) {
res += s[tmp];
}
}
}
return res;
}
};
Python3代码:
class Solution:
def convert(self, s: str, numRows: int) -> str:
if len(s) <= 1 or numRows == 1:
return s
temp = 2 * numRows - 2
res = ""
for i in range(0, numRows):
for j in range(i, len(s), temp):
res += s[j]
if i != 0 and i != numRows - 1 and j + temp - 2 * i < len(s):
res += s[j + temp - 2 * i]
return res