将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"
示例 2:
输入: s = "LEETCODEISHIRING", numRows = 4
输出: "LDREOEIIECIHNTSG"
解释:
L D R
E O E I I
E C I H N
T S G
这道题刚开始看了半天没看懂是咋样变换的,上网查了些资料,终于搞懂了,就是要把字符串摆成一个之字型的,参考了网上这位仁兄的解法 (http://www.cnblogs.com/springfor/p/3889414.html)。
比如有一个字符串 “0123456789ABCDEF”,转为zigzag
当 n = 2 时:
0 2 4 6 8 A C E
1 3 5 7 9 B D F
当 n = 3 时:
0 4 8 C
1 3 5 7 9 B D F
2 6 A E
当 n = 4 时:
0 6 C
1 5 7 B D
2 4 8 A E
3 9 F
我们发现,除了第一行和最后一行没有中间形成之字型的数字外,其他都有,而首位两行中相邻两个元素的index之差跟行数是相关的,为 2*nRows - 2, 根据这个特点,我们可以按顺序找到所有的黑色元素在元字符串的位置,将他们按顺序加到新字符串里面。对于红色元素出现的位置也是有规律的,每个红色元素的位置为 j + 2*nRows-2 - 2*i, 其中,j为前一个黑色元素的列数,i为当前行数。 比如当n = 4中的那个红色5,它的位置为 1 + 2*4-2 - 2*1 = 5,为原字符串的正确位置。当我们知道所有黑色元素和红色元素位置的正确算法,我们就可以一次性的把它们按顺序都加到新的字符串里面。解析在代码中:
class Solution {
public:
string convert(string s, int numRows) {
string convert_s = "";
int length_s = s.size();
if(numRows <=1)//错:这句和下面这句没加,当行数<=1,只有一行时,应该直接返回s
return s;
int door = 2 * numRows - 2;
//这是一道找规律的题,主要是找黑色和红色字符的位置,黑色字符的间隔是 2 * numRows - 2,而红色字符间隔是j + door - 2 * i(i是上一个黑色字符行数,j是黑色字符列数)
//第一个for循环是控制行数,第二个for循环是控制黑色字符的列数,然后convert_s += s[j];就是向convert_s加入黑色字符
//而当i不是第一行和最后一行时,就会包括红色字符,而红色字符间隔是j + door - 2 * i,则在黑色字符之间插入符合条件的红色字符,用黑色字符控制插入红色字符的起点convert_s += s[k];
for (int i = 0; i < numRows;i++)//错:i < length_s改为numRows
{
for (int j = i; j < length_s;j+=door)
{
int k = j + door - 2 * i;
convert_s += s[j];//错:(1)convert_s[i] += s[door];改为convert_s += s[door];(2)s[door]改为s[j]
if (i!=0&&i!=numRows-1&&k<length_s)
{
convert_s += s[k];
}
}
}
return convert_s;
}
};