題目:
將一個給定字串 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;
}
};
結果如下: