题目:
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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
分析:
所谓Z字形即也可说是倒N形,将字符串按下标顺序排列成一个个倒N形。思路用numRows个数组来表示每一行该有的元素,最终结果则是遍历这numRows个数组,而Z字形的规律也很容易找到,可将其分为两部分:1.倒N的一竖,翻译成程序即为numRows个数组每个都依次(正序)添加一个元素。2.倒N的一瞥,翻译成程序即为从numsRows-2到1的数组依次(逆序)添加一个元素。最后程序的终止原字符串遍历完。然后依次输出各个数组元素。
代码:
public static String convert(String s, int numRows) {
char[] a = s.toCharArray();
char[][] b = new char[numRows][a.length];
int [] len = new int[numRows];
int index=0;
while(index<a.length) {
for(int i=0;i<numRows&&index<a.length;i++) {
b[i][len[i]++] = a[index++];
}
for(int i=numRows-2;i>0&&index<a.length;i--) {
b[i][len[i]++] = a[index++];
}
}
StringBuffer sb = new StringBuffer();
for(int i=0;i<numRows;i++) {
for(int j=0;j<len[i];j++) {
sb.append(b[i][j]);
}
}
return sb.toString();
}
优化:
采用找规律的方式也能够很容易找到每一行字符下标的规律。
(1)第一行和第numRows行属于特殊情况,他们只出现在倒N的一竖上,顺序跳跃查找,例如第一行,初始i=0,查找a[i](a为原字符串s所对应的字符数组),然后i = i + 2 * (numRows - 1);
(2) 居于第一行和第numRows中间的行,由于他们在倒N的一竖和一瞥上均有元素,一竖上的元素下标递增方式为
i + 2 * (numRows - 1),由一竖找到下一个一瞥的方式为i + 2 * (numsRows - i - 1);
代码:
public static String convert1(String s, int numRows) {
if(numRows==1) {
return s;
}
char[] a = s.toCharArray();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < numRows; i++) {
int p = i;
while (p < a.length) {
sb.append(a[p]);
if (i != 0 && i != numRows-1 && (p + 2 * (numRows - i - 1))<a.length) {
sb.append(a[p + 2 * (numRows - i - 1)]);
}
p = p + 2 * (numRows - 1);
}
}
return sb.toString();
}
注意:上边(1)中公式i = i + 2 * (numRows - 1),当numRows==1时i不会增加,所以需要在这种算法中判断numRows==1.