ZigZag Conversion (C实现)

来源:互联网 发布:sdl区域分割算法 编辑:程序博客网 时间:2024/05/01 07:39
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   NA P L S I I GY   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变成k步之字形的字符串,然后在按行重新排列。如下图:

解析:这题其实就是一个下标转换的问题,目标字符串的第i个字符对应的是原字符串的第j个字符,找到 j=f (i)的转换方法即可。举个例子来说,源字符串:ABCDEFGHIJKLM,k = 4;转化后如下图所示:

第一张表是原字符串中的下标,第二张表中的黑色下标识转换后的下表,红色是原下标,通过这个表可以看出几个问题:

  1. 第一行与最后一行的字符比较少,原因很简单,我们假设有一个人手里拿着N个字符,每走过一行放下一个字符,一次之字形来回首末两行只走过一次,而中间行会走过两次,所以当手里的字符无限多的时候,首末两行的字符数量要比中间行的字符数量少一半。

  2. 把第二张表的奇数列拿出来,可以看出来第一列ABCD的原下标是0123(即原下标号对应行号-1,行号从1开始),第三列GHIJ的原下标是6,7,89,对应行的原下标差6,第五列M的原下标是12等于G的原下标6+6,由此我们可以得出一个结论,只要确定了第一列的原下标,就能确定奇数列的字符原下标,而相邻奇数列的下标差为2*(k-2)+2。

  3. 如果单独摘出偶数列的字符,很难发现它们之间有明显的规律,此时要结合偶数列与前一奇数列来看,E的原下标4 = C的原下标2+2,增量2是如何得来的呢?从C之字形走到EC所在的第三行走到最后一行需要走4-3步,然后再从最后一行走回第三行还是需要4-3步,所以2=2*(4-3),因此可以得出一般结论,偶数列的原下标=前一奇数列的原下标+2*(k-i),i为行号,从1开始。

代码实现:

char* convert(char* s, int numRows) {    int strLen = strlen(s), counter = 0;//counter计数器,记录目标字符串的当前下标    char *ret = malloc((strLen+1)*(sizeof(char)));    if(numRows == 1 || numRows >= strLen) //特殊情况,不需要转化{        return s;}    else {        for(int i = 1; i <= numRows; i++) {            for(int j = i; j <= strLen; j += 2*numRows-2) //奇数列的原下标每次递增2*numRows-2{                ret[counter++] = s[j-1];                if(1 != i &&  i != numRows && j+2*(numRows-i) <= strLen) //当不是第一行与最后一行时,需要计算偶数列的下标{                    ret[counter++] = s[j+2*(numRows-i)-1];}}}}    ret[strLen] = '\0';    return ret;}




0 0
原创粉丝点击