Zigzag Conversion
- Easy
- tag: String, Math
- similar: rotate graph, count ones
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 text, int nRows)
- convert("PAYPALISHIRING", 3) should return "PAHNAPLSIIGYIR".
思路
先搞明白这个zigzag什么意思: Ans: 就是根据row和string, 变成zigzag的形状. 例如row = 5的时候如下图:
0 1 2 3 0 0 1 1 2 2 3 0 0 1 1 2 2 . 0 0 1 1 2 2 . 0 1 2
题目要求返回变为zigzag之后再按行打印出来. 一开始的想法是建立新的表, 然后一行行的打印. 那么一共有多少列呢? 怎么排列呢? 感觉挺麻烦的.
idea : discuss里面tju_xu的解法
- 还是和rotate graph一样, 这题很有规律. 看到这里有个循环, 即上图中所示的相同index的
V
型. 可以很容易计算出这个循环体的长度:numRows+(numRows-2) = numRows * 2 - 2
. 因为第一行/最后一行只有cycle中的1个元素, 其他行都有该cycle中的2个元素. 那么怎么找到在原本的string中的index呢?
- 对于第i行:
- 对于第一个元素: $$j = i + cycle * k ; k \in [0,1,2...]$$
- 是个很好理解.
- 该cycle中, 该行的第二个元素的index是: $$secondj = (j-i) + cycle + i$$.
- 这里j-i即该cycle的起点, j-i+cycle即下一个cycle的起点, 于是第二个元素就从下一个cycle的起点向前推i个就是了.
公式有了就很容易写了, 但还是要注意怎么loop.
- 这里是按照结果的顺序, 即按行loop. 从而按顺序加入结果string.
代码如下:
public String convert(String s, int numRows) {
if (numRows <= 1) return s;
int cycle = numRows * 2 - 2;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numRows; ++i) {
// Suppose the current row is i, the index of the first element is j
for (int j = i; j < s.length(); j += cycle) {
sb.append(s.charAt(j));
// (j-i) is the start of current period, (j-i) + cycle is the start of next periods
int secondJ = (j-i) + cycle - i;
if (i != 0 && i != numRows-1 && secondJ < s.length()) {
sb.append(s.charAt(secondJ));
}
}
}
return sb.toString();
}