LeetCode #443 Medium

String Compression

String Compression: compress the character array in place by replacing each run of repeats with the character followed by its count, and return the new length. Runs of length 1 keep no count.

Constraints
  • 1 <= chars.length <= 2000
  • chars[i] is a lowercase English letter, uppercase English letter, or digit.
stringtwo-pointers
Open on LeetCode ↗
02

Intuition

Two pointers with different jobs: a read pointer that scans runs, and a write pointer that lays down the compressed output behind it. The write pointer can never overtake the read pointer, because a run of length L produces at most 1 + digits(L) characters, which never exceeds L. That is why in-place is safe.

How to spot this pattern

Read and write pointers moving at different speeds is the in-place-rewrite pattern — the same as Remove Duplicates from Sorted Array and Move Zeroes. The reusable insight is proving the write pointer lags the read pointer, which is what licenses mutating the array you are still scanning.

03

Approach

Try it first

Before reading on: convince yourself the write pointer can never pass the read pointer. Then work out what a run of twelve identical characters should actually place in the array. Aim for O(n) with O(1) space.

1

Separate reading from writing

Keep read for scanning and write for output. At each run, note the character, advance read while the same character repeats, and compute the run length. Then write the character at write, and if the length exceeds 1, write its digits too. Because compression never expands, write stays at or behind read and the not-yet-read tail is never clobbered — this is the invariant that makes the whole thing legal in place.

2

Multi-digit counts must be written digit by digit

A run of 12 becomes the characters '1' and '2', not a single element holding 12. Convert the number to its string form and write each digit separately. Forgetting this is the classic bug: it passes on runs under 10 and breaks on longer ones, which small hand-tested examples never expose.

3

Return length, not string

The problem asks for the new length; the caller reads only the first write entries. Anything beyond that is ignored, so there is no need to truncate or clear the tail. Time is O(n) — each element is read once and written at most once — with O(1) extra space, which is the entire point of the exercise.

04

Solution & live demo

1class Solution:
2 def compress(self, chars):
3 write = 0
4 read = 0
5 while read < len(chars):
6 char = chars[read]
7 length = 0
8 while read < len(chars) and chars[read] == char:
9 read += 1
10 length += 1
11 chars[write] = char
12 write += 1
13 if length > 1:
14 for digit in str(length):
15 chars[write] = digit
16 write += 1
17 return write
05

Common pitfalls

Writing a multi-digit count as one element

✗ Wrong
chars[write] = str(length)
✓ Right
for digit in str(length):
    chars[write] = digit
    write += 1

A count of 12 must occupy two array slots, '1' and '2'. Storing "12" in a single slot passes tests with short runs and fails the moment a run reaches ten.

Writing a count of 1

✗ Wrong
chars[write] = char
write += 1
for digit in str(length): ...
✓ Right
if length > 1:
    for digit in str(length): ...

The specification says a single character is left alone. Writing 'a1' both lengthens the output and produces the wrong answer.

Returning the array instead of the length

✗ Wrong
return chars
✓ Right
return write

The problem's contract is to mutate in place and return how many entries are meaningful. The judge reads the first write characters; returning the array fails the signature.

06

Edge cases

No repeats, e.g. ['a','b','c']

Every run has length 1, so no counts are written and the length is unchanged at 3.

Run of exactly 2, e.g. ['a','a']

Writes 'a' then '2', giving length 2 — the same length, still correct.

Run of 10 or more, e.g. twelve 'a's

Writes 'a','1','2' — the count is split into separate digit characters.

Single character

One run of length 1; the answer is 1 with no count written.

Run at the very end

The inner while stops at the array bound, so the final run is written like any other.

07

Complexity

Time
O(n)
Space
O(1)
Each element is read once and written at most once; the digit conversion is bounded by four characters.