LeetCode - 6. ZigZag Conversion

題目:

The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)

P   A   H   N
A P L S I I G
Y   I   R

And then read line by line: "PAHNAPLSIIGYIR"

Write the code that will take a string and make this conversion given a number of rows:

string convert(string text, int nRows);

convert("PAYPALISHIRING", 3) should return "PAHNAPLSIIGYIR".

 

解題思路:

        找出原來字符串s中合適位置的元素,給新的之字形字符串zgStr中的字符按順序賦值。所以問題的關鍵即找出原s和新的zgStr之間的對應關係,即數學推導公式

        由於得到之字形結果後,要按行輸出結果,所以容易想到,推導zgStr中每行的字符與原s中字符的位置關係。

數學推導過程:

        首先,當numRows等於1或者大於等於s的長度時,返回原來的s即可;

        然後,計算推導公式:

        顯然,之字形結果的第一行和最後一行是按原s中間隔 2*numRows-2 依次輸出;

        對中間行,可分別得奇數位置與偶數位置直接的遞推關係:

        所以原來的思路一直侷限於怎麼找出這兩個關係,並且通過怎樣的循環來賦值輸出。結果雖然可以分別推導出奇數位置和偶數位置的遞推關係,但是無法用一個遞推公式推導出合在一起的結果。

    並且原來的思路一直是先判斷是否是最後一行,然後賦值輸出;再專門對中間行進行處理。但是一直進行不下去。

    後來看了DISCUSS裏的解答之後,才忽然明白,不需要推導兩個相鄰位置的遞推關係。

    因爲中間行的奇數位置上和第一行、最後一行的關係一樣,所以可以一起處理,不需要單獨處理開頭結果和中間行;並且只需要找到偶數位置與其上一個位置(奇數位置)的關係即可!

        這樣先按照間隔 2*numRows-2 輸出一個元素,然後判斷是不是開頭結尾行,若不是再輸出一個(即接下來的偶數位置的)。

    而偶數位置與其上一個位置的關係在之前的遞推公式中也得到。

 

C程序實現:

char* convert(char* s, int numRows) {
    int sLen = strlen(s);
    int c = 0;  //之字形數組zgStr的下標
         char* zgStr = malloc((sLen+1)*sizeof(char));
    if(numRows == 1 || numRows >= sLen){
        return s;
    }
    else{
        for(int i=1; i<=numRows; i++){
            for(int j=i; j<=sLen; j+=2*numRows-2){
                zgStr[c++] = s[j-1];
                if(i!=1 && i!=numRows && j+2*(numRows-i)<=sLen) //再對中間行的偶數位置單獨處理一次
                   		      zgStr[c++] = s[j-1+2*(numRows-i)];
            }
        }
    }
    zgStr[sLen]='\0';   //別忘了最後的結束
    return zgStr;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章