題目:
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;
}