File: design-compressed-string-iterator/solution.py

Date: 2026-06-06

Time: 16:17

design-compressed-string-iterator/solution.py

Purpose

This file implements LeetCode 604 — Design Compressed String Iterator. It provides a StringIterator class that lazily decompresses a run-length encoded string one character at a time, without ever materializing the full expanded string. The file also contains its own test suite inline.

Key Components

StringIterator — The core class. Constructed with a compressed string like "L1e2t1C1o1d1e1" where each letter is followed by its repetition count (which can be multi-digit).

Patterns

Lazy cursor-based parsing. Rather than pre-parsing all (char, count) pairs into a list, the iterator maintains a read cursor (i) and only parses the next pair when the current one is fully consumed. This gives O(1) memory regardless of how large the counts are — important since counts can reach 10^9 (see testlarge_count).

Sentinel-based exhaustion. When the input is consumed, the iterator falls into a terminal state where char = ' ' and count = 0. The space character doubles as both the sentinel and the return value for next() after exhaustion — this matches the LeetCode spec exactly.

Self-contained test module. Tests live in the same file via unittest.TestCase and run with python -m unittest or python solution.py. A separate test_solution.py exists alongside it for the project's test harness.

Dependencies

Imports: Only unittest from the standard library. No external dependencies.

Imported by: The massive Imported By list in the repo context is misleading — those are cross-references from a code-expert indexing tool, not actual Python imports. The real consumer is design-compressed-string-iterator/test_solution.py, which imports StringIterator from this module.

Flow

1. Constructor receives "a12b3", stores it, sets cursor _i = 0.

2. extractnext() reads s[0]'a', scans digits s[1:3]"12", sets char = 'a', count = 12, advances _i = 3.

3. Each next() call returns 'a' and decrements count. On the 12th call, count hits 0 and extractnext() fires again: reads 'b', count 3, _i = 5.

4. After 3 more next() calls, extractnext() finds i >= len(s), sets the sentinel state.

5. Subsequent next() calls return ' ' indefinitely.

Invariants

Error Handling

There is none. The code trusts its input per the LeetCode contract. If s contains no digits after a character, int(self.s[self._i:j]) would receive an empty string and raise ValueError. This is by design — the problem guarantees valid input.