ZigZag Conversion
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"
.
按照它题目给出来的例子,不熟悉的话,还真不知道他想我们干嘛,所以还是看看图样就清楚了,如下面的运行打印图:
8行的时候
5行的时候
10行的时候
这就清楚了,利用输入字符打印一个倒立之字形的图样。
关键是要会如何计算各个字符的位置,这就需要数学知识了,根据特殊推导出公式来。
主要是3个公式:
1 之字形行数为nRows,那么每次重复样出现前的间隔字符为zigSpan= nRows*2-2;
2 第一行和最尾一行都是存放一个字符的,所以存储的字符为间隔为zigSpan的字符
3 中间行是需要额外存储多一个字符的,存储的字符位置是: zigSpan + j - 2*i(其中i为行数,j为该行第几个字符了)
如下面程序:
class Solution {
public:
string convert(string s, int nRows)
{
if(nRows <= 1 || s.length() < 3 || s.length() <= nRows) return s;
string s2;
int zigSpan = nRows*2 - 2;
for (int i = 0; i < nRows; i++)
{
for (int j = i; j < s.length(); j+=zigSpan)
{
s2.push_back(s[j]);
//注意:推导出zigSpan+j-2i的数学公式,一点都不能错
if (i != 0 && i != nRows-1 && zigSpan+j-2*i<s.length())
{
s2.push_back(s[zigSpan+j-2*i]);
}
}
}
return s2;
}
};
下面是打印测试程序,运行结果如前面看到的图样:
void printZigzag(const string &s, int nRows)
{
if(s.empty() || nRows < 1) return;
if (nRows == 1)
{
cout<<s<<endl;
return;
}
int zigSpan = nRows*2 - 2;
int zig = nRows - 2;
for (int i = 0; i < nRows; i++)
{
for (int j = i; j < s.length(); j+=zigSpan)
{
cout<<s[j];
//注意:推导出zigSpan+j-2i的数学公式,一点都不能错
if (i != 0 && i != nRows-1 && zigSpan+j-2*i<s.length())
{
for (int r1 = 0; r1 < zig-i; r1++)
{
cout<<" ";
}
cout<<s[zigSpan+j-2*i];
for (int r2= 0; r2 < i-1; r2++)
{
cout<<" ";
}
}
else
{
for (int r = 0; r < zig; r++)
{
cout<<" ";
}
}
}
cout<<endl;
}
}
int main()
{
string str1 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
Solution solu;
int nRows = 5;
//string str2 = solu.convert(str1, nRows);
//cout<<str2<<endl;
printZigzag(str1, nRows);
system("pause");
return 0;
}
2014-1-24 update
解决此类题:画图,根据图,仔细观察,然后按例子计算,最后得出公式
string convert(string s, int nRows)
{
//测试少了这句,居然是 Memory Limit Exceeded 错误
//主要是不能没有nRows===1这句判断,Leetcode喜欢这么设计,没办法。
//不用额外判断应该本程序也是可行的。
if(nRows <= 1 || s.length() < 3 || s.length() <= nRows) return s;
string rs;
int span = nRows*2-2;
for (int i = 0; i < nRows && i < s.length(); i++)
{
rs.push_back(s[i]);
int j = i+span;
for (; j < s.length(); j+=span)
{
if (i != 0 && i != nRows-1) rs.push_back(s[j-i*2]);
rs.push_back(s[j]);
}
//注意这句的判断条件,不能少
if (i != 0 && i != nRows-1 && j-i*2<s.length()) rs.push_back(s[j-i*2]);
}
return rs;
}