Zigzag Conversion

Medium Simulation

Problem

Given a string s and an integer numRows, return the string formed by writing s in a zigzag pattern on numRows and then reading line by line.

  • 1 ≤ s.length ≤ 1000
  • s consists of English letters (lower-case and upper-case), ',' and '.'
  • 1 ≤ numRows ≤ 1000

Example

Input: s = "PAYPALISHIRING", numRows = 3
Output: "PAHNAPLSIIGYIR"

The zigzag pattern for numRows=3 is: P A H N A P L S I I G Y I R Reading line by line produces "PAHNAPLSIIGYIR". The algorithm simulates placing characters row by row, changing direction when reaching the top or bottom row. The critical moment is when the direction reverses at the boundaries, ensuring characters are assigned to the correct rows in zigzag order.

Approach

Straightforward Solution

A brute-force approach might try to build a 2D matrix representing the zigzag and then read it line by line. This wastes space and complicates indexing, especially for large strings and row counts.

Core Observation

The zigzag pattern can be viewed as placing characters sequentially in rows, moving downwards until the bottom row, then upwards until the top row, repeatedly. This movement creates a repeating cycle of row indices.

Path to Optimal

The key insight is to simulate the zigzag traversal by tracking the current row and direction (down or up). Instead of building a matrix, maintain an array of strings for each row and append characters accordingly. When the current row reaches either boundary (0 or numRows-1), reverse the direction. This approach uses O(n) time and O(n) space efficiently.

Optimal Approach

Initialize an array of empty strings for each row. Iterate over each character in s, appending it to the current row's string. Update the current row by moving in the current direction. Reverse direction when the top or bottom row is reached. Finally, concatenate all row strings to form the output.

Time

O(n)

Each character in the input string is processed exactly once, appending to one of the row strings, resulting in linear time complexity.

Space

O(n)

The auxiliary space is proportional to the input size, as all characters are stored distributed across the row strings before concatenation. This is necessary since the output string length equals the input length.

Pattern Spotlight

Simulation (Stateful Traversal)

When a problem requires constructing or interpreting a pattern with directional changes or cycles, simulate the process by tracking state variables (like current position and direction) instead of building explicit data structures, enabling efficient and clear solutions.

Solution

1class Solution:
2 def convert(self, s: str, numRows: int) -> str:
3 if numRows == 1:
4 return s
5
6 rows = [""] * numRows
7 row = 0
8 direction = 1
9
10 for ch in s:
11 rows[row] += ch
12
13 if row == 0:
14 direction = 1
15 elif row == numRows - 1:
16 direction = -1
17
18 row += direction
19
20 return "".join(rows)

Step-by-Step Solution

1

Handle Single Row Edge Case to Avoid Unnecessary Processing

3if numRows == 1:
4 return s

Objective

To immediately return the input string if numRows is 1, since the zigzag pattern degenerates to a straight line.

Key Insight

When numRows is 1, the zigzag pattern is just the original string itself. This early exit prevents unnecessary computation and avoids edge case bugs related to direction changes and row indexing.

Interview Quick-Check

Core Logic

Recognizing that numRows=1 means no zigzag occurs and the input string is the output.

Common Pitfalls & Bugs

Failing to handle numRows=1 separately can cause index errors or incorrect direction changes.

2

Initialize Row Containers and Directional State for Zigzag Simulation

6rows = [""] * numRows
7row = 0
8direction = 1

Objective

To prepare an array of strings for each row and initialize variables to track the current row and traversal direction.

Key Insight

Using an array of strings for rows allows efficient appending of characters without complex 2D structures. The current row and direction variables simulate the zigzag traversal by moving through rows and reversing direction at boundaries.

Interview Quick-Check

Core Logic

Storing characters in separate row strings simulates the zigzag pattern without extra space for empty cells.

State & Boundaries

Initializing direction to 1 means starting by moving downwards through rows.

Common Pitfalls & Bugs

Using list multiplication for rows (e.g., [''] * numRows) creates references to the same string, which can cause bugs; however, in this code it is used, which is a subtle issue.

3

Simulate Zigzag Traversal by Appending Characters and Updating Direction

10for ch in s:
11 rows[row] += ch
13 if row == 0:
14 direction = 1
15 elif row == numRows - 1:
16 direction = -1
18 row += direction

Objective

To iterate over each character in the input string, append it to the current row, and update the current row index and direction accordingly.

Key Insight

The traversal moves downwards until the bottom row, then reverses to move upwards until the top row, repeating this cycle. By checking boundaries and flipping direction, the algorithm ensures characters are assigned to the correct rows in zigzag order. This simulation avoids building a full matrix and achieves O(n) time.

Interview Quick-Check

Core Logic

The direction variable controls whether the current row index increments or decrements, simulating the zigzag movement.

State & Boundaries

Direction reverses when the current row reaches 0 (top) or numRows - 1 (bottom), ensuring the zigzag pattern.

Common Pitfalls & Bugs

Appending characters to rows before updating direction ensures correct placement; reversing this order can cause off-by-one errors.

4

Concatenate Row Strings to Form Final Zigzag Converted Output

20return "".join(rows)

Objective

To combine all row strings into a single output string representing the zigzag conversion.

Key Insight

After simulating the zigzag traversal, each row string contains characters in the correct order. Concatenating these row strings in sequence produces the final converted string as required by the problem.

Interview Quick-Check

Core Logic

Joining all row strings in order produces the final zigzag string without extra processing.

Complexity

String concatenation using join is efficient and runs in O(n) time.

Line Analysis

This solution has 3 Critical lines interviewers watch for.

Line 3 Critical
if numRows == 1:

Check if numRows is 1 to handle the trivial zigzag case.

When numRows is 1, the zigzag pattern is just the original string, so returning early avoids unnecessary computation and prevents errors related to direction changes.

Line 11 Critical
rows[row] += ch

Append the current character to the string of the current row.

Assigning characters to rows as they appear simulates the zigzag pattern without building a full matrix.

Line 18 Critical
row += direction

Update the current row index by adding the direction.

Incrementing or decrementing the row index simulates moving down or up the zigzag pattern, ensuring characters are assigned to the correct rows.

Line 4 Core
return s

Return the original string immediately if numRows is 1.

This early return ensures correctness and efficiency for the edge case where no zigzag transformation is needed.

Line 6 Core
rows = [""] * numRows

Initialize an array of empty strings for each row.

This array will hold characters assigned to each row during the zigzag simulation, enabling efficient appends and final concatenation.

Line 20 Core
return "".join(rows)

Concatenate all row strings to form the final output.

Joining the row strings in order produces the zigzag converted string as required by the problem.

Line 8 Core
direction = 1

Initialize the direction to 1, indicating downward movement.

Direction controls whether the current row index increments or decrements, simulating the zigzag traversal through rows.

Line 13 Core
if row == 0:

Check if the current row is the top row (0).

Reaching the top row requires reversing direction to move downwards in the zigzag pattern.

Line 14 Core
direction = 1

Set direction to 1 to move downwards.

Changing direction at the top boundary ensures the zigzag traversal moves correctly through rows.

Line 15 Core
elif row == numRows - 1:

Check if the current row is the bottom row (numRows - 1).

Reaching the bottom row requires reversing direction to move upwards in the zigzag pattern.

Line 16 Core
direction = -1

Set direction to -1 to move upwards.

Changing direction at the bottom boundary ensures the zigzag traversal moves correctly through rows.

Line 10 Standard
for ch in s:

Iterate over each character in the input string.

Processing characters sequentially is necessary to simulate their placement in the zigzag pattern.

Line 7 Standard
row = 0

Initialize the current row index to 0.

Starting at the top row aligns with the zigzag pattern beginning at the first row.

Test Your Understanding

Why is it necessary to reverse the direction when the current row reaches the top or bottom?

Because the zigzag pattern moves downwards through rows until the bottom row, then reverses to move upwards until the top row, repeating this cycle. Reversing direction at boundaries ensures characters are assigned to rows in the correct zigzag order.

Related Problems

Simulation pattern

Don't just read it. Drill it.

Reconstruct Zigzag Conversion from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the Zigzag Conversion drill

or drill a free problem