題目:
將一個給定字符串根據給定的行數,以從上往下、從左到右進行 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.