[LeetCode] 6. ZigZag Conversion 之字形变换
The string "PAYPALISHIRING"
is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H N A P L S I I G Y I R
And then read line by line: "PAHNAPLSIIGYIR"
Write the code that will take a string and make this conversion given a number of rows:
string convert(string s, int numRows);
Example 1:
Input: s = "PAYPALISHIRING", numRows = 3 Output: "PAHNAPLSIIGYIR"
Example 2:
Input: s = "PAYPALISHIRING", numRows = 4 Output: "PINALSIGYAHRPI" Explanation: P I N A L S I G Y A H R P I
Example 3:
Input: s = "A", numRows = 1 Output: "A"
Constraints:
1 <= s.length <= 1000
s
consists of English letters (lower-case and upper-case),','
and'.'
.1 <= numRows <= 1000
这道题刚开始看了半天没看懂是咋样变换的,上网查了些资料,终于搞懂了,就是要把字符串摆成一个之字型的,比如有一个字符串 "0123456789ABCDEF",转为 zigzag 如下所示:
当 numRows = 2 时:
0 2 4 6 8 A C E
1 3 5 7 9 B D F
当 numRows = 3 时:
0 4 8 C
1 3 5 7 9 B D F
2 6 A E
当 numRows = 4 时:
0 6 C
1 5 7 B D
2 4 8 A E
3 9 F
可以发现,除了第一行和最后一行没有中间形成之字型的数字外,其他都有,而首尾两行中相邻两个元素的 index 之差跟行数是相关的,为 2*nRows - 2, 根据这个特点,可以按顺序找到所有的黑色元素在原字符串的位置,将它们按顺序加到新字符串里面。对于红色元素出现的位置(Github 上可能无法正常显示颜色,请参见博客园上的帖子)也是有规律的,每个红色元素的位置为 j + 2*numRows-2 - 2*i, 其中,j为同一行前一个黑色数字的在原字符串中的位置 index,i为当前行数。 比如当 n = 4 中的那个红色5,它的位置为 1 + 2 x 4-2 - 2 x 1 = 5,为原字符串的正确位置。知道了所有黑色元素和红色元素位置的正确算法,就可以一次性的把它们按顺序都加到新的字符串里面。代码如下:
解法一:
class Solution { public: string convert(string s, int numRows) { if (numRows <= 1) return s; string res; int size = 2 * numRows - 2, n = s.size(); for (int i = 0; i < numRows; ++i) { for (int j = i; j < n; j += size) { res += s[j]; int pos = j + size - 2 * i; if (i != 0 && i != numRows - 1 && pos < n) res += s[pos]; } } return res; } };
若上面解法中的规律不是很好想的话,我们也可以用下面这种更直接的方法来做,建立一个大小为 numRows 的字符串数组,为的就是把之字形的数组整个存进去,然后再把每一行的字符拼接起来,就是想要的结果了。顺序就是按列进行遍历,首先前 numRows 个字符就是按顺序存在每行的第一个位置,然后就是 ‘之’ 字形的连接位置了,可以发现其实都是在行数区间 [1, numRows-2] 内,只要按顺序去取字符就可以了,最后把每行都拼接起来即为所求,参见代码如下:
解法二:
class Solution { public: string convert(string s, int numRows) { if (numRows <= 1) return s; string res; int i = 0, n = s.size(); vector<string> vec(numRows); while (i < n) { for (int pos = 0; pos < numRows && i < n; ++pos) { vec[pos] += s[i++]; } for (int pos = numRows - 2; pos >= 1 && i < n; --pos) { vec[pos] += s[i++]; } } for (auto &a : vec) res += a; return res; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/6
类似题目:
Binary Tree Zigzag Level Order Traversal
参考资料:
https://leetcode.com/problems/zigzag-conversion/
https://www.cnblogs.com/springfor/p/3889414.html
https://leetcode.com/problems/zigzag-conversion/discuss/3403/Easy-to-understand-Java-solution