题目地址
https://leetcode-cn.com/problems/zigzag-conversion/
题目描述:Z 字形变换
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。
再比如输入字符串为 “LEETCODEISHIRING” 行数为 4 时,排列如下:
L D R
E O E I I
E C I H N
T S G
请你实现这个将字符串进行指定行数变换的函数:string convert(string s, int numRows);
解答
这个问题并不复杂。
方法一:按行排序
首先给出一个较为直观的算法,利用辅助空间(二维数组),使用向上/向下标记来选定方向,构造 Z 字形字符串。
代码:
class Solution {
public:
string convert(string s, int numRows) {
// 当 numRows == 1 时, 返回原字符串
if( numRows == 1)
return s;
//当numRows == 2时, 返回原数组中字符交替
if( numRows == 2){
string res;
for( int i = 0; i < s.size(); i+=2)
res +=s[i];
for( int i = 1; i < s.size(); i+=2)
res += s[i];
return res;
}
// 以下情况适合于 numRows >= 3 时,此时存在一个 Z 型
//为了方便,创建足够大的辅助空间
vector< vector< char>> record( numRows, vector<char>( s.size()));
int down = 1, count = 0;
int temp = numRows;
for( int i = 0; i < s.size(); i++)
if( down){
record[ numRows - temp][count] = s[i];
temp--;
if( !temp)
temp = numRows - 2, down = 0, count++;
}
else{
record[ temp][count++] = s[i];
temp--;
if( !temp)
temp = numRows, down = 1;
}
string res;
for( int i = 0; i < numRows; i++)
for( int j = 0; j < s.size(); j++)
if( record[i][j])
res += record[i][j];
return res;
}
};
//时间复杂度为O( numRows * s.size())
// 可以通过优化空间,将算法运行时间优化到到 O(n)
方法二:按行访问。(依据下标的规律)
首先读取第 0 行的字符,之后读取第 1 行, 第 2 行,…,第 numRows - 1 行的字符。
对于所有的整数 k:
- 第 0 行的字符位于索引 k( 2 * numRows - 2) 处;
- 第 numRows - 1 行中的字符位于索引 k * (2 * numRows - 2) + numRows - 1 处;
- 内部第 i 行的字符位于索引 k(2numRows - 2) + i 和 (k+1)( 2numRows) - i处。
class Solution {
public:
string convert(string s, int numRows) {
if (numRows == 1) return s;
string res;
int cycleLen = 2 * numRows - 2;
for (int i = 0; i < numRows; i++) { //
for (int j = 0; j + i < s.size(); j += cycleLen) {
res += s[j + i];
if (i != 0 && i != numRows - 1 && j + cycleLen - i < s.size())
res += s[j + cycleLen - i];
}
}
return res;
}
};
// 改算法运行时间为O(n)