题目如下:
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"
刚看到这道题的时候,动手在纸上画了下,发现第一行字符出现的下标在原始字符串中是有规律的,ai = i(2 * row - 2),紧接着找下面的行,找了几分钟无果。本着先解决问题的态度,打算暴力解下,使用二维数组,遍历字符串,逐个字符读取到数组中,最后再从数组中读取出来。这个想法阔以,点提交的时候提示超出时间限制.......暴力无果,卒。
重新找规律,其实规律也不是那么难找,第一行和最后一行规律基本上都是i(2*row - 2),中间行的字符规律看似不好找,不是。
每个字符与下一个字符是对称的。例如题目中的第二行,前两个字符ET和第一行终点E对称,距离为n - i,n为总行数,i为第i行。
此外就是第一个数和第二数是对称的,第二个数和第三个数也是对称的,只不过对称的距离不同,稍稍总结下可得每行字符下标规律:
设行数为i,那么第i行第k个元素下标右下列式子可得:
当i为首行或者尾行时,Ak = (i - 1) + 2(row - 2);
当i为中间行时,A1 = i - 1;
Ak = Ak-1 + (k%2 ? (row - i) : (i - 1));
知道了规律,就可以按行从原始字符串中读取字符了。
看了官方给的按行读取方法,顺序读取字符串,添加到行中,每读取一个字符,添加到一行中,同时指向下一行,当到了行尾或者行首则改变行的方向。方法是不错,不过如果用c语言实现的话,不是还得为每一行申请一块内存吗?这块内存大小又不能确定,这和数组法有啥区别。
下面是找规律的c代码:
char * convert(char * s, int numRows){
int len = 0, row = 0, i = 0, j = 0, k = 0;
char *pstr;
pstr = s;
if (!s || numRows < 2)
return s;
while (*pstr++ != '\0')len++;
if (len < 2)
return s;
pstr = (char *)malloc(sizeof(char) * (len + 1));
if (!pstr)
return NULL;
i = 0;
for (row = 1; row <= numRows; row++)
{
//按行读取每个字符下标
j = row - 1;
if (row == 1 || row == numRows)
{
while (j < len)
{
pstr[i++] = s[j];
j += (2 * numRows - 2);
}
}
else
{
k = 1;
while(j < len)
{
pstr[i++] = s[j];
j = j + ((k++ % 2) ? 2 * (numRows - row) : 2 * (row - 1));
}
}
}
pstr[i] = '\0';
return pstr;
}
编码的时候挖了一个坑," ?: "三目运算符的优先级低于加号,导致运算有问题!!!
参考资料:
1. 数据结构 : C语言版/ 严蔚敏,吴伟民编著
=============================================================================================
Linux应用程序、内核、驱动开发交流讨论群(745510310),感兴趣的同学可以加群讨论、交流、资料查找等,前进的道路上,你不是一个人奥^_^。