Problem
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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
Solving
暴力排序法
直接将原字符串排列成Z型
0 第一轮 2n-2 第二轮 4n-4 . . . k(2n-2)
1 2n-3 2n . . 第k轮 . k(2n-2)+1
. . . . . . . length-1
. n+1 . . . . . .
. n . . . . . .
n-1 3n-3 . .
根据示意图,我们输出后的索引顺序应该是0,2n-2,4n-4,…k(2n-2),1…
我们可以根据length的值可以先计算出k值。
显然,除了第一行和最后一行,在每一轮中,插入的是两个元素。我们按照下面的方式往新字符串中插入字符:
从上往下从左往右依次插入。i从0到n,上闭下开,先从第0行开始;col从0到k,左闭右开,依次插入col*(2n-2+i),再判断,k(2n-2)是否小于length,小于即表示未超过原有字符串,继续插入。最后一行和第0行都是插入一个字符,可以使用同一段代码;而中间几段都是插入2个字符,也可以一起处理,以i为第一行为例,col从0到k,左闭右开,依次插入col*(2n-2+i),(col+1)*(2n-2-i),同样再判断第k+1轮的字符是否超过原字符串。所以最终的代码如下
Code(c++)
class Solution {
public:
string convert(string s, int numRows) {
if (numRows<2) // 行数少于2行时,不需变换
return s;
string res;
int k = s.length()/(2*numRows-2); // k轮完整的z(以一下一上为一轮Z)
for(int i=0; i<numRows; ++i){ // 按输出子串顺序,从原子串中暴力寻找
if (i>0 && i<numRows-1){
for(int col=0; col<k; ++col){
res.push_back(s[col*(2*numRows-2)+i]);
res.push_back(s[(col+1)*(2*numRows-2)-i]);
}
if(k*(2*numRows-2)+i<s.length())
res.push_back(s[k*(2*numRows-2)+i]);
if((k+1)*(2*numRows-2)-i<s.length())
res.push_back(s[(k+1)*(2*numRows-2)-i]);
}
else{
for(int col=0; col<k; ++col){
res.push_back(s[col*(2*numRows-2)+i]);
}
if(k*(2*numRows-2)+i<s.length())
res.push_back(s[k*(2*numRows-2)+i]);
}
}
return res;
}
};
执行用时 :16 ms
内存消耗 :9.7 MB