题目:
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 RAnd 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"
.思路:
1.本题旨在按照字符串绘制一个类似于Z字形的折线,然后按行重现构造字符串;
2.构造形式如下图所示:
3.在图中,nRows为6(即表格上下共有6条线,每条代表1行),每个表格中数据代表其左上角所存字符在原字符串中位置;
4.按照题意,结果将按照0-10-20-1-9-11-19-21-2-8-12-28-22···的顺序重新构造;
5.由于行数给定(如6),那么我们可以考虑按照行数遍历得出新的字符串;
6.观察图得知:在第0行(及最后一行)中,两个点之间的差为10,原因在于,此值为0点下的点个数与10一下的点个数之和,在第0行下共有nRows-1行,除最后一行外每行有两个点,计算10=2*(nRows-1)-1+1,那么除外后一行外,设此时为第i行,若观察点此时在偶数列(如点1),则下一点(9)到该点的距离为2*(nRows-i-1)-1+1,若观察点在奇数列(点9),下一点至改点距离为(2*(nRows-1)-1+1)-(2*(nRows-i-1)-1+1);
7.在6中计算出了在任意一行两点之间距离的计算公式,依照这些公式,就可以按行遍历,得出每一行的字符串,然后将这些字符串拼接,即可得出最后的字符串;
8.其实本题思路为两层遍历,先按行遍历,在每一行中再按列遍历,但是由于本题获取列数并不方便,所以只要时刻保证当前下标小与原始字符串即可,这样可以作为列遍历的限制;
9:本算法对字符串仅遍历一次,故时间复杂度为O(n);
代码:
class Solution{
public:
string convert(string s, int nRows){
int len=s.length();
if(len==0 || nRows<=1)
return s;
string result="";
for(int i=0;i!=nRows && i!=len;++i)
{
result+=s[i];
int step=0;
int idx=i;
for(int c=0;idx<len;++c)
{
if(i==0 || i==nRows-1)
step=2*(nRows-1);
else
{
if(!(c%2))
step=2*(nRows-1-i);
else
step=2*(nRows-1)-2*(nRows-1-i);
}
idx+=step;
if(idx<len)
{
result+=s[idx];
}
}
}
return result;
}
};