题目:
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);示例 1:
输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"
示例 2:
输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P I N
A L S I G
Y A H R
P I
示例 3:
输入:s = "A", numRows = 1
输出:"A"
上面就是题目的内容,难度标注的是中等,拿到题目读了有一会儿,刚开始不是很懂,后面看了示例大概明白了一些。
我当时的第一反应是进行字符串抽点,Z形应该是有规律可以找的,我设置了row = 3,4,5分别进行了规律查找:
当row = 3时,输入“PAYPALISHIRING”,通过观察Z形,可以看到下标0的P到A时需要有3个字符间隔,下标为1的A到P有1个字符间隔,到Y到I的字符间隔和第1个P到A的字符间隔一致。
但是需要注意的是,当row = 4或5时,其字符间隔会发生变化且数值有两种可能。如下所示(row = 4):
A到L的字符间隔数和L到S的字符间隔数会发生变化,且只有两种情况。
按此推论,从row = 3,4,5的情况下的字符排布,得出各行到下一个字符的间隔数遵循下述规律:
nums=2*(row-1-index)-1;
nums是字符间隔数,row是输入的行数,index是要拼接的每行的下标(若row=6,那么index=[0,5])
当row=4:
index=0,nums=5
index=1,nums=3
index=2,nums=1
index=3,nums=5(同index=0的情况)
也就是说index=0的P到I,中间需要跨5个字符,index=1的A到L需要跨3个字符,但是L到S需要跨1个字符,所以当row为偶数时,需要前后对称构成一组进行遍历,当row为奇数时,中间的index只需要按自己的nums进行遍历。
我提交的代码如下:
class Solution {
public:
string convert(string s, int numRows) {
if(numRows == 1)
return s;
int* index = new int[numRows]{};
for (int i = 0; i < (numRows % 2 == 0 ? numRows / 2 : numRows / 2 + 1); ++i) {
if (i == (numRows - 1 - i)) {
index[i] = 2 * (numRows - 1 - i) - 1;
}
else {
index[i]= 2 * (numRows - 1 - i) - 1;
index[numRows -1-i]= i == 0 ? index[i] : 2 * (numRows - 1 - (numRows - 1 - i)) - 1;
}
}
int now_index = 0;
std::string output;
for (int i = 0; i < numRows; ++i) {
now_index = i;
std::string temp;
bool flag = true;
int a = index[i] + 1;
int b = index[numRows - 1 - i] + 1;
while (now_index < s.length()) {
temp += s[now_index];
now_index += flag ? a : b;
flag = !flag;
}
output += temp;
}
delete[] index;
return output;
}
};
结果如下: