(6)ZigZag Conversion
题目:字符串“PAYPALISHRING”写的是一个给定的字符串,写成这样一个曲折模式:
P A H N
A P L S I I G
Y I R
然后逐行读取:“PAHNAPLSIIGYIR”。
编写代码,会提供需要的字符串和变换成的行数:
string convert(string text, int nRows);
convert(“PAYPALISHIRING”,3)需要返回”PAHNAPLSIIGYIR”。
看到这道题就想到了原来学习C语言做的输出图形之类的题目,感觉很简单,唯一的问题就在于如何推导关系公式,在纸面上自己画了一下,看了一看就获取了每个位置的关系公式。
首先定义一个单位,将整个转换后的ZigZag图形分成一个一个小的单位,就比如我将左侧开始从第一列到第n-1列分为一个小单元,这样每个小单元组成一个整个的图形。
每个单元中的数字分别为:
1 (2n-1)(这个位置其实是下一个单元的第一个数字)
2 2n-2
3 ·
· ·
· ·
· n+2
n-1 n+1
n
这样我们可以发现,每个数字的关系其实就是如上图所示,我们发现第一列的数字其实就是行数,行数的上限就是题目的numRows,但是可能有人觉得在这个图中第二列往后的每列数字不好和行数关系起来,那么不妨我们分析一下,(n-1) + (n+1) = 2n, 2+(2n - 2) = 2n,那我们可以转换成下图
1 2n-1
2 2n-(2)
3 ·
· ·
· ·
· 2n-(n-2)
n-1 2n-(n-1)
n
这样我们就找到了解题的方式了,除了第一行和最后一行, 每一行的分别是行数i以及(2n-i)这两个字符,然后每一个小单位里面一共有2n-2个单位字符,那么下一个单位就是每个字符加上2n-2,每次判断是否超过长度就可以了。
另外我们需要考虑一个问题就是2n-2有可能为零,此时n=1,我们需要添加一条就是n=1的时候直接返回原字符串就可以了,因为以1做ZigZag就是本身。
代码如下:
class Solution {
public:
string convert(string s, int numRows) {
int i = 1, j = 0;
int len = s.size();
string str = "";
if( numRows == 1){
return s;
}
for(i = 1; i <= numRows; i ++){
if(i == 1|| i == numRows){
j = i;
while(j <= len){
str += s.substr(j-1, 1);
j += (2*numRows - 2);
}
}
else{
j = i;
int k = ((2*numRows)-j);
while(j <= len){
str += s.substr(j-1, 1);
if(k <= len){
str += s.substr(k-1, 1);
}
j += (2*numRows - 2);
k += (2*numRows - 2);
}
}
}
return str;
}
};