题意简述:将一个字符串以连续的N字形排列转存到二维矩阵后按行依次输出得到一个新字符串。
输入:原字符串s,二维矩阵行数nRows。
输出:二维矩阵按行输出的结果(空白部分不输出)。
示例:输入为(”PAYPALISHIRING”, 3),输出为”PAHNAPLSIIGYIR”,排列如下所示。
P A H N
A P L S I I G
Y I R
题解:
先以一个例子观察是否存在规律,假设原字符串长度为16,nRows=4,则可以得到字符串下标排列
0 6 12
1 5 7 11 13
2 4 8 10 14
3 9 15
这样可能看不出什么,但是如果加上竖线分割的话,可以发现一些规律:
|0 |6 |12
|1 5 |7 11 |13
|2 4 |8 10 |14
|3 |9 |15
- 从二维矩阵的角度看,排列存在周期,周期为6(=2*(nRows-1)),周期数为3(=字符串长度/周期,再向上取整)。
- 从行的角度看,对于首尾两行,从起始下标(0和3(=nRows-1))开始,每个周期下标+6;对于中间的行,起始下标其实有两个(1和5(=周期-1)、2和4(=周期-2)),每个周期两个下标分别+6。
也就是说,按行来循环处理(首尾两行单独处理),完全可以根据以上的规律按顺序确定下一个字符对应原字符串的哪个下标的字符,并不需要真的构造一个二维字符矩阵。因此只需要新声明一个string,按顺序将对应的原字符串的字符向后插入,最后返回该string即可。
此算法的时间复杂度和空间复杂度均为O(N)。
string convert(string s, int numRows) {
if(numRows == 1)
return s;
int period = 2 * (numRows - 1);
int looptime = (s.size() - 1) / period + 1;
string mystr;
for(int i = 0;i*period < s.size();i++) {
mystr.push_back(s[i*period]);
}
for(int i = 1;i < numRows - 1;i++) {
for(int j = 0;j < looptime;j++) {
if(i + period * j < s.size())
mystr.push_back(s[i+period*j]);
if(period - i + period * j < s.size())
mystr.push_back(s[period-i+period*j]);
}
}
for(int i = 0;numRows-1+i*period < s.size();i++) {
mystr.push_back(s[numRows-1+i*period]);
}
return mystr;
}