1. 程式人生 > 其它 >LeetCode No6 Z字形變換

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();
    }
}