题目描述
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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:
观察以上两个示例可以得出结论:每一横行每个字符之间间隔的字符数量都是一定的,所以找到其中的规律就可以迎刃而解。
第一横行的第一个字符是s字符串的第一个字符,第二横行的第一个字符是s字符串的第二个字符。对于示例二而言,第一横行的L和D之间,D和R之间,间隔5个字符。第二横行E与O,E与I相差3个字符,O与E,I与I相差1个字符,找到这些规律之后,就可以写代码了。
public static String convert(String s, int numRows) {
if (s.length() < 3 || numRows == 1)
return s;
String str = "";
int rows = 1; // 用来计算第几行
int num = 2 * numRows - 3; // 第一行和最后一行跳过的个数
int index = 0; // 当前指针所指的位置
while (str.length() < s.length()) {
if (rows == 1 || rows == numRows) {
// 当index超过s的长度之后,表示当前行已经全部遍历完毕
while (index < s.length()) {
str += s.charAt(index);
index += num + 1;
}
} else {
int Upnum = (rows - 2) * 2 + 1; // 向上跳过的个数
int DownNum = (numRows - rows - 1) * 2 + 1; // 向下跳过的个数
int flag = -1; // -1 表示向下,1表示向上
while (index < s.length()) {
str += s.charAt(index);
if (flag == -1) {
index += DownNum + 1;
flag = 1;
} else {
index += Upnum + 1;
flag = -1;
}
}
}
index = rows;
rows++;
}
return str;
}
方法2:
先初始化一个字符串数组,将每个字符放到对应的行即可。具体思路参考下图
public static String convert(String s, int numRows) {
if (s.length() < 3 || numRows == 1)
return s;
String strList[] = new String[numRows];
for (int i = 0; i < numRows; i++)
strList[i] = "";
int rows = 0;
int flag = 1; // 1 表示向下,-1表示向上
for (int i = 0; i < s.length(); i++) {
strList[rows] = strList[rows] + s.charAt(i);
rows += flag;
if (rows == numRows - 1)
flag = -1;
if (rows == 0)
flag = 1;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numRows; i++) {
sb.append(strList[i]);
}
return sb.toString();
}
第二种方法实现的思路较简单,所以时间复杂度和内存消耗比方法1好,如果大家也有不错的方法,我们可以一起讨论。