问题描述:
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"
.
说说我一开始怎么想的吧,通过观察我发现,在完整的一列到下一个完整的列之间会有一些空白的地方,我把这些空白的长度叫做gap,空白的个数叫做gap_num,观察发现gap=nRows-2,gap_num=nRows-1,知道这个规律以后我们只要创建一个二维数组,以列的形式读入字符串再以行的形式输出字符串就是我们需要的答案了。
#include <string.h> char* convert(char* s, int numRows) { int len = strlen(s), rows = numRows; char *bucket = (char *)malloc((len*numRows) * sizeof(char)); char *p; int gap = numRows - 2, gap_num = numRows - 1; int i=0, j, k = 0; for (p = bucket; p < bucket+len*numRows; p++) *p = 0; p = bucket; if(len==0||numRows==1) return s; while (s[i] != ‘\0‘) { while (rows-->0&&s[i]!=‘\0‘) { *p = s[i++]; p++; } while (gap_num-->0&&s[i]!=‘\0‘) { gap = numRows - 2; while (gap-->0) p++; *p = s[i++]; p++; } gap_num = numRows - 1; rows=numRows-1; } char *answer =(char *) malloc((len + 1) * sizeof(char)); for (i = 0; i<numRows; i++) for (j = 0; j<len; j++) { if (*(bucket + j*numRows + i) != 0) answer[k++] = *(bucket + j*numRows + i); } answer[k]=‘\0‘; return answer; }
代码写得有点渣,不过这不是我想要的最终的算法嘛,随便写写,能AC就好。AC之后发现这个算法真是有够慢的,那么我当然得想一个更快的算法了。稍微考虑一下我发现,这个算法慢在两个地方,一是中间数组bucket,如果我能不经过中间数组而直接得到结果的话速度应该会快不少。二是空白的处理,想想我之前用while去处理真是太傻了点。
#include <string.h> char* convert(char* s, int numRows) { int len = strlen(s), row = 0; int gap=2*numRows-2,gap_1,gap_2=0,i=0,j=0; char *answer =(char *) malloc((len + 1) * sizeof(char)); if(numRows==1||len==0) return s; while(row<numRows){ gap_1=gap-gap_2; i=row; answer[j++]=s[i]; while(1){ i=i+gap_1; if(i>=len) break; if(gap_1!=0) answer[j++]=s[i]; i=i+gap_2; if(i>=len) break; if(gap_2!=0) answer[j++]=s[i]; } row++; gap_2+=2; } answer[j]=‘\0‘; return answer; }
这是改进后的代码,时间从166ms提升到了9ms,效果还是挺显著的。思路的话简单来说就是通过观察规律直接将原字符串转为需要的答案字符串。我发现的规律是gap(也就是从完整两列之间的距离)为2*numRows-2。完整两列之间同行的数有3个(包括完整列上的数,首行和末行把第二列上的数算两次)。第一个到第二个的距离,我记为gap_1,第二个到第三个记为gap_2。容易看出gap_1+gap_2==gap,并且所在行数每增加1,gap_2就减少2。有了这个规律,就很容易写出上面的代码了。