LeetCode No6 Z字形變換
題目
將一個給定字串 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 <= 1000
s 由英文字母(小寫和大寫)、',' 和 '.' 組成
1 <= numRows <= 1000
思路
模擬
題目的操作並不複雜,可以直接按照題目意思直接模擬,將字串轉化成一個矩陣,然後再遍歷矩陣即可得到最後的字串。但是這種方式提交很容易超時,而且構建出的矩陣有很大部分都是浪費掉了。
直接構造
相對於模擬得到最後的矩陣,其實我們並不在意最後的矩陣到底是什麼樣子的,我們如果能夠明白構建矩陣的規律,那麼就可以直接按照規律去取數,不需要真正的構建矩陣,那麼我們先研究下當行數numRows 小於4的時候分別是什麼樣子。
numRows 為1:
0 1 2 3 4 5 6 7 ... n
numRows 為2:
0 2 4 6 ... n-1 1 3 5 7 ... n
numRows 為3
0 4 8 12 1 3 5 7 9 11 2 6 10
numRows 為4
0 6 12 18 1 5 7 11 13 17 2 4 8 10 14 16 3 9 15
可以看到其實所有的變幻操作都是在迴圈的打鉤 [ √ ],以numRows=4為例:
0 | 6 | 12 |18 1 5 | 7 11 | 13 17 |19 23 2 4 | 8 10 | 14 16 |20 22 3 | 9 | 15 |21
而每次打鉤 [ √ ]所需要的字元個數t也是和numRows有關:
當numRows=1時:t=1 當numRows=2時:t=2 當numRows=3時:t=4 當numRows=4時:t=6 ... 當numRows=n時:t=2*n-2
那這樣我們就可以推斷出numRows=n的時候,所迴圈的鉤 [ √ ]應該如下[t=2*n-2]:
0 1 t-1 2 t-2 3 t-3 4 t-4 5 t-5 6 t-6 ...... n-1
那這個時候我們只需要用for迴圈按行去讀取對應的字元,也就不需要在程式碼中構建出最後的矩陣了。
AC程式碼
模擬
點選檢視程式碼
class Solution {
public String convert(String s, int numRows) {
if( numRows == 1 ) {
return s;
}
char[] chars = s.toCharArray();
int len = chars.length;
char[][] charss = new char[numRows][len];
int i = 0;
int j = 0;
int index = 0;
while( index<len ) {
if( i==0 ) {
if( j!=0 ) {
// 第一次的時候是以第一行為起點,其他迴圈次數的時候是一第二行為起點
i ++;
}
while( i < numRows && index<len ) {
charss[i][j] = chars[index];
i ++;
index ++;
}
i --;
}
if( i == numRows-1 ) {
while(i>0 && index<len ) {
i --;
j ++;
charss[i][j] = chars[index];
index ++;
}
}
}
StringBuffer sb = new StringBuffer();
for(i=0; i<numRows; i++) {
System.out.println();
for(j=0; j<len; j++) {
System.out.print(charss[i][j] + " ");
if(Character.isLetter(charss[i][j]) || charss[i][j]=='.' || charss[i][j]==',') {
sb.append(charss[i][j]);
}
}
}
return sb.toString();
}
}
直接構造
點選檢視程式碼
class Solution {
public String convert(String s, int numRows) {
int len = s.length();
if (numRows == 1 || numRows >= len) {
return s;
}
char[] chars = s.toCharArray();
StringBuffer sb = new StringBuffer();
int t = numRows * 2 - 2;
for (int i = 0; i < numRows; ++i) {
// 迴圈打√
for (int j = 0; j + i < len; j += t) {
sb.append(chars[j+i]);
// 找一次迴圈的第二個值,同時第一行和最後一行只有一個值,不需要找
if (0 < i && i < numRows - 1 && j + t - i < len) {
sb.append(chars[j + t - i]);
}
}
}
return sb.toString();
}
}