Problem:
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"
.
分析:
先分析一下题意,将字符串按ZigZag方式排列,并按序输出。何为ZigZag,我按下标顺序表示如下,其中row = 5
0 | 6 | 12 | 18 | ||||||
1 | 5 | 7 | 11 | 13 | 17 | 19 | |||
2 | 4 | 8 | 10 | 14 | 16 | ||||
3 | 9 | 15 |
每整列(图中用红色标出)的间隔为6,
第一行:下标分别为0、6、12、18 -> 每个整列数字间隔为6
第二行:下标分别为1、5、7、11、13、17、19 ->每个整列数字间的间隔分别两部分,左半边为4,右半边为2
第三行:下标分别为2、4、8、10、14、16 -> 每个整列数字间的间隔分别两部分,左半边为2,右半边为4
第四行:下标分别为3、9、15 -> 每个整列数字间隔为6
结果按第一行至第四行分别输出。
故由上面的直观分析可知:
每整列的间隔为circule = 2*numRows - 2,即numRows + numRow - 2,numRow - 2为去除首位后的长度
第i行的输出的起始下标为i,按circule分割为一个个子部分,每部分又分为左右两半,左半长为cirLeft = circule - 2 * i,右半长为circule - cirLeft。
注意:
在提交时出现过Time Limit Exceeded和Output Limit Exceeded的问题,主要原因都是未考虑边界问题。
1、numRows = 1时要另外处理,因为此时直接计算circule = 2 * numRows - 2 = 0
2、s.size() <= numRows可直接输出
3、当每次更新当前下标位置index时,如index + cirLeft,index + circule,一定要考虑是否越界,而不止是每次在while时检查。
AC Code (C++):
class Solution {
public:
//1158 / 1158 test cases passed.
//Runtime: 27 ms
string convert(string s, int numRows) {
if (s.size() <= numRows || numRows <= 1) {
return s;
}
string output;
int circule = (numRows << 1) - 2;//每一轮包含多少个字符
for (int cirLeft = circule, i = 0; cirLeft >= 0; cirLeft -= 2, ++i) {
int strIndex = i;
output.push_back(s[strIndex]);
cout<<output.size()<<'\t'<<output<<endl;
while (strIndex < s.size()) {
if (cirLeft != 0 && strIndex + cirLeft < s.size()) {
output.push_back(s[strIndex + cirLeft]);
cout<<output.size()<<'\t'<<output<<endl;
}
strIndex += circule;
if(cirLeft != circule && strIndex < s.size()){
output.push_back(s[strIndex]);
cout<<output.size()<<'\t'<<output<<endl;
}
}
}
return output;
}
};