Site Search:

Zigzag string

Problem

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:
P   A   H   N
A P L S I I G
Y   I   R

Input: s = "PAYPALISHIRING", numRows = 4
Output: "PINALSIGYAHRPI"
Explanation:

P     I    N
A   L S  I G
Y A   H R
P     I

PAYPALISHIRING

Solution

This kind of problem test if we can handle large amount of details in a reasonable time. We need to walk through a few special cases and form a formula. The formula can calculate the index or space between indexes, the variables are number of lines k, row number i and column number j.

Here is an example formula:
We divide the zigZag into many V shapes. We can increase j by 2k - 2 to get the next V shape on the right.

To calculate the space between the first index and second index on the V shape, we  we can use formula  j + 2k - 2 - 2i. 

0         10              20               k = 6
1      9 11        19 21               2*(k-i) - 2 = 2 * (6-1) -2 = 8
2    8   12      18   22               2k - 2 - 4
3   7    13    17     23                      - 6
4 6      14  16       24                      - 8
5         15              25

0,    6,       12,    |18     j + 2k - 2
1, 5,7   11 13,    |19     j + 2k - 2 - 2i
2,4, 8 10   14,    |20     j + 2k - 2 - 2i
3,    9        15,    |21     j + 2k - 2

class ZigZag {
  //PAYPALISHIRING  -> PINALSIGYAHRPI
  //    .
  //PINALSIGYA
  //time O(N), space O(N)
  public static String transform(String str, int k) {//4
    if(k == 1) return str;
    char[] a = str.toCharArray();
    int N = a.length;//14
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < k; i ++) { //2
      if(i == 0 || i == k - 1) {
        for(int j = i; j <= N - 1; j+=(2*k - 2)) //6
          sb.append(a[j]);
      } else {
        for(int j = i; j <= N - 1; j+=(2*k - 2)) {//2
          sb.append(a[j]);
          if(j + 2*k - 2 - 2*i < N - 1) {
            sb.append(a[j + 2*k - 2 - 2*i]);  //2 + 8 - 2 - 4 = 4
          }
        }
      }
    }
    return sb.toString();
  }
  public static void main(String...args) {
    String str = "PAYPALISHIRING";
    System.out.println(transform(str, 3));
  }
}

We visited each character once, the time complexity is O(N). A StringBuilder is used to store the converted string so the space complexity is O(N) as well.