题目:
ZigZag指的是将字符串按Z字形(锯齿形)排列,如字符串“123456789”,当numRows为3时,排列顺序如下图:
题目要求我们将字符串按锯齿形排列后按行重新组合,如上面的例子,新组合的字符串为“0481357926”。
解法一:
为每一行申请一个字符串保存重新排列后的字符,数字按Z字形铺排时有两个方向,数值向下和斜向上,用布尔变量forth来保存当前方向:向下时字符串数组的下标加一,斜向上时字符串数组的下标减一。最后将每个字符串逐序想加即得到结果。需要遍历一遍给出字符串的字符,时间复杂度为o(n)。需要考虑numRow=1时的特殊情况。Accepted的代码如下:
class Solution {
public:
string convert(string s, int numRows) {
string results;
string temp[10000]="";
int currentRow=0;
bool forth=1;//延伸的方向,1为向下
if(numRows==1) results=s;
else
{
for(int i=0;i<s.size();i++)
{
//向下
if(forth)
{
temp[currentRow]+=s[i];
currentRow++;
if(currentRow==numRows)
{
currentRow=currentRow-2;
forth=0;
}
}
//斜向上
else
{
temp[currentRow]+=s[i];
currentRow--;
if(currentRow==-1)
{
currentRow=currentRow+2;
forth=1;
}
}
}
for(int i=0;i<numRows;i++)
{
results+=temp[i];
}
}
return results;
}
};
解法二:
解法一的效率很低,在网上看到这一题其实是有规律可循的:所有行的重复周期都为numRows*2-2,而除首行和末行外,中间的行每经一个重复周期,中间多重复一个数,重复数距本周期起始字符的距离为2*numRows-2-2* i。如:
第一行和最后一行的两个数之间相差2*3-2=4,中间一行1和5之间还插入了一个与1相差2*3-2-2*1=2的3。按这个规律,可以根据给定字符串的下标得到重排的字符串。虽然算法的时间复杂度为o(n^2),但这里的n为numRows,大大小于字符串长度,同时节省了空间复杂度。Accepted的代码如下:
class Solution {
public:
string convert(string s, int numRows) {
string results="";
if (numRows==1) return s;
int t=2*numRows-2; //循环周期
for(int i=0; i<numRows;i++)
{
int j=i;
//首行和末行
if(i==numRows-1||i==0)
{
while(j<s.size())
{
results+=s[j];
j=j+t;
}
}
//中间行
else
{
while(j<s.size())
{
results+=s[j];
if(j+t-2*i<s.size()) results+=s[j+t-2*i];
j=j+t;
}
}
}
return results;
}
};
可以看到效率大大提高: