Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions problems/0006-zigzag-conversion/analysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# 0006. Zigzag Conversion

[LeetCode Link](https://leetcode.com/problems/zigzag-conversion/)

Difficulty: Medium
Topics: String
Acceptance Rate: 53.4%

## Hints

### Hint 1

Think about how characters are distributed across rows. Instead of trying to build the zigzag pattern visually, consider collecting all characters that belong to each row separately.

### Hint 2

The zigzag pattern has a repeating cycle. Characters move down through rows 0, 1, 2, ..., numRows-1, then move back up through numRows-2, numRows-3, ..., 1, then down again. Track which direction you're moving (down or up) as you iterate through the string.

### Hint 3

Create an array of strings (or string builders) - one for each row. As you iterate through the input string, append each character to the appropriate row based on the current direction. When you hit the top or bottom row, reverse the direction.

## Approach

The key insight is that we don't need to actually construct the 2D zigzag pattern. Instead, we can simulate the zigzag movement and collect characters for each row.

**Algorithm:**
1. Handle edge cases: if numRows is 1 or the string length is less than numRows, return the original string
2. Create a slice of strings (one for each row) to collect characters
3. Initialize two variables:
- `currentRow` to track which row we're currently on (starts at 0)
- `goingDown` to track whether we're moving down or up (starts as false, will flip to true)
4. Iterate through each character in the string:
- Append the character to the string for `currentRow`
- If we're at the top row (0) or bottom row (numRows-1), flip the direction
- Move to the next row: increment if going down, decrement if going up
5. Concatenate all row strings together and return

**Example walkthrough with "PAYPALISHIRING", numRows = 3:**
- Row 0: P (↓), A (↑), H (↑), N (↑)
- Row 1: A (↓), P (↓↑), L (↓), S (↓↑), I (↓), I (↓↑), G (↓)
- Row 2: Y (↓), I (↑), R (↑)
- Result: "PAHNAPLSIIGYIR"

The cycle length is `2 * numRows - 2` (down numRows steps, up numRows-2 steps).

## Complexity Analysis

Time Complexity: O(n) where n is the length of the string. We iterate through the string once, and each character is appended to a row exactly once.

Space Complexity: O(n) for storing the characters in row strings. The final result also requires O(n) space.

## Edge Cases

1. **numRows = 1**: No zigzag pattern possible, return the original string
2. **String length ≤ numRows**: The zigzag won't complete a full cycle, but the algorithm handles this naturally
3. **Single character string**: Should return as-is
4. **String shorter than numRows**: Characters only go down, never zigzag back up
43 changes: 43 additions & 0 deletions problems/0006-zigzag-conversion/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

// Approach: Simulate the zigzag pattern by collecting characters for each row
// As we iterate through the string, we track which row we're on and whether
// we're moving down or up. When we hit the top or bottom row, we reverse direction.
// Finally, concatenate all rows to get the result.

func convert(s string, numRows int) string {
// Edge case: if only 1 row or string is too short, no zigzag needed
if numRows == 1 || len(s) <= numRows {
return s
}

// Create a slice to hold characters for each row
rows := make([]string, numRows)
currentRow := 0
goingDown := false

// Iterate through each character and append to appropriate row
for _, char := range s {
rows[currentRow] += string(char)

// Reverse direction when we hit top or bottom row
if currentRow == 0 || currentRow == numRows-1 {
goingDown = !goingDown
}

// Move to next row
if goingDown {
currentRow++
} else {
currentRow--
}
}

// Concatenate all rows
result := ""
for _, row := range rows {
result += row
}

return result
}
64 changes: 64 additions & 0 deletions problems/0006-zigzag-conversion/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package main

import "testing"

func TestConvert(t *testing.T) {
tests := []struct {
name string
s string
numRows int
expected string
}{
{
name: "example 1: PAYPALISHIRING with 3 rows",
s: "PAYPALISHIRING",
numRows: 3,
expected: "PAHNAPLSIIGYIR",
},
{
name: "example 2: PAYPALISHIRING with 4 rows",
s: "PAYPALISHIRING",
numRows: 4,
expected: "PINALSIGYAHRPI",
},
{
name: "example 3: single character",
s: "A",
numRows: 1,
expected: "A",
},
{
name: "edge case: numRows is 1",
s: "ABCDEFGH",
numRows: 1,
expected: "ABCDEFGH",
},
{
name: "edge case: string length equals numRows",
s: "ABC",
numRows: 3,
expected: "ABC",
},
{
name: "edge case: string shorter than numRows",
s: "AB",
numRows: 5,
expected: "AB",
},
{
name: "edge case: two rows",
s: "ABCDE",
numRows: 2,
expected: "ACEBD",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := convert(tt.s, tt.numRows)
if result != tt.expected {
t.Errorf("convert(%q, %d) = %q, want %q", tt.s, tt.numRows, result, tt.expected)
}
})
}
}