题目:Z 字形变换:
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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:找规律
如图为例,可以看出:
- 起始编号都是行号;
- 第 0 层和第 n 层的下标间距都是 step = (2n-2)
- 中间层的间距始终是 (step - 2*行数 )和 (2*行数) 交替
- 判断结束的标准是下表不能超过 len(s) - 1
- 注意特殊情况:只有一行时候直接输出
代码如下:
class Solution {
public:
string convert(string s, int numRows) {
int step = numRows * 2 - 2; // 间距
string ans;
if(numRows == 1){
return s;
}
for(int i = 0; i < numRows; i++){//i表示行号
int cur = i;// 记录当前位置的下标
if(i == 0 || i == numRows - 1){
while(cur < s.size()){
ans += s[cur];
cur += step;
}
}
else{
while(cur < s.size()){
ans += s[cur];
cur += step - 2*i ;
if(cur >= s.size()) break;
ans += s[cur];
cur += 2*i;
}
}
}
return ans;
}
};
2. 按行排序
从左到右按箭头方向迭代 s ,将每个字符添加到合适的行。之后从上到下遍历行即可。使用当前行和当前方向这两个变量对合适的行进行跟踪。
class Solution {
public:
string convert(string s, int numRows) {
if (numRows == 1) return s;
vector<string> rows(min(numRows, int(s.size())));// 防止s的长度小于行数
int curRow = 0;
bool goingDown = false;
for (char c : s) {
rows[curRow] += c;
if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;// 当前行curRow为0或numRows -1时,箭头发生反向转折
curRow += goingDown ? 1 : -1;
}
string ret;
for (string row : rows) ret += row;
return ret;
}
};
链接:https://leetcode-cn.com/problems/zigzag-conversion/solution/z-zi-xing-bian-huan-by-leetcode/