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