Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Coding Interview Patterns  Module 28 – String patterns

String to integer (atoi) and run-length encoding

Parse a clamped 32-bit number from text typed by people, and decode run-length codes with counts of several digits: the problems and where direct code breaks.

  • Intermediate
  • 30 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free intro, Pro: 8 of 30 minutes free
Free: Two problems on a meter's data · The direct code, and the inputs that break it. With a pass: the other 9 sections and 3 interview answers, about 22 minutes.

What you will learn

  • Parse the integer at the start of messy text and clamp it to the 32-bit range without ever overflowing
  • Prove that the overflow check before each digit is exact at both ends of the range
  • Compare what the parsers of Python, Java, C++, Go and JavaScript accept and reject
  • Decode and encode run-length codes whose counts have several digits
  • Rewrite a character array in place with its run-length code, and prove that the writer never passes the reader

Before you start

What you’ll learn · Before you start

What you will learn

  • Parse the integer at the start of messy text and clamp it to the 32-bit range without ever overflowing
  • Prove that the overflow check before each digit is exact at both ends of the range
  • Compare what the parsers of Python, Java, C++, Go and JavaScript accept and reject
  • Decode and encode run-length codes whose counts have several digits
  • Rewrite a character array in place with its run-length code, and prove that the writer never passes the reader

Before you start

On this page

String to integer, often called atoi after the C function, means reading the number at the start of a piece of text: skip leading spaces, accept one sign, read digits until the first other character, and clamp the value to the 32-bit range instead of letting it overflow. Run-length encoding stores a string as runs, each a letter and how many times it repeats, so aaabcc becomes a3bc2. Both are simulations whose difficulty lies in the edge cases: a number or a count with many digits, a value past the limit, a sign with nothing after it. This lesson states both problems, shows where the direct code breaks at the stated sizes, and what to notice before writing the loops.

Two problems on a meter’s data

Problem A: string to integer. A smart-meter app receives readings typed by people. Write parse_clamped(s): skip leading spaces, read at most one + or -, then the ASCII digits that follow, and stop at the first other character. Return the value clamped to −2³¹ … 2³¹ − 1, or 0 if no digit follows. Limits: 0 ≤ len(s) ≤ 10⁵.

  • " -0042 kWh" gives −42, and "+-12" gives 0, because the second sign is not a digit.
  • "9999999999" gives 2,147,483,647, and " + 7" gives 0: a space after the sign ends the number.

Problem B: run-length encoding. The meter’s sensors report status letters, sent run-length encoded: each run is its letter followed by its length, which is left out when it is 1. Write rle_decode(code), and compress(chars), which rewrites a list of letters in place with its encoding and returns the new length. Counts can have several digits, and runs can be 10⁵ letters long.

  • "a3bc2" decodes to "aaabcc", and "x12" to twelve x’s.
  • compress(list("aaabcc")) returns 5, the list starting a3bc2; compress(list("abc")) returns 3.
The reading " -0042 kWh" read character by character, giving −42, and the code a3bc2 decoded run by run into aaabcc.Reading the meterDecoding a3bc2␣skip␣skip-sign000044242␣stopa3aaabbc2cc

Problem A reads characters until the first non-digit; problem B reads a letter and then its count

Text description of the diagram

The diagram has two rows, one under the other.

  1. The start of the reading " -0042 kWh" is drawn as eight cells, each with a character and what the parser does with it. The two spaces are skipped. The minus sign is read as the sign. The digits 0, 0, 4 and 2 are read one at a time, and the value after each is 0, 0, 4 and 42. The space after the 2 stops the parser, so the rest, kWh, is never read. With the sign, the result is −42.
  2. The code a3bc2 is drawn as three runs: a3 decodes to aaa, b with no count decodes to a single b, and c2 decodes to cc. Together they give aaabcc.

The direct code, and the inputs that break it

The first idea for problem A reads all the digits into one variable and clamps at the end. A reading of 10⁵ digits overflows any fixed-size integer long before the end, and a 64-bit variable silently wraps: 18446744073709551621, which is 2⁶⁴ + 5, comes out as 5. Python’s integers never overflow, but int() refuses more than 4,300 digits by default, the limit CPython sets on decimal conversion. For problem B, reading each digit as a separate count turns x12 into one x.

Clamping at the end, int() on 5,000 digits, and one digit per count Python · direct/direct_attempts.py
# The direct versions of both problems, and the inputs that break them.
LOW, HIGH = -(2**31), 2**31 - 1


def wrap64(x):
    """What a signed 64-bit variable holds after x overflows it (Java's long, Go's int64)."""
    x %= 2**64
    return x - 2**64 if x >= 2**63 else x


def parse_then_clamp(s, wrap):
    """Read the number into one variable and clamp at the end; wrap=True imitates a 64-bit variable."""
    i = 0
    while i < len(s) and s[i] == " ":
        i += 1
    sign = -1 if i < len(s) and s[i] == "-" else 1
    if i < len(s) and s[i] in "+-":
        i += 1
    value = 0
    while i < len(s) and "0" <= s[i] <= "9":
        value = value * 10 + int(s[i])
        if wrap:
            value = wrap64(value)
        i += 1
    return min(max(sign * value, LOW), HIGH)


for reading in ["  -0042 kWh", "9999999999", "18446744073709551621 kWh"]:
    print(f"{reading!r:28} 64-bit: {parse_then_clamp(reading, True):>11}   exact: {parse_then_clamp(reading, False):>11}")

try:
    int("7" * 5000)
except ValueError as e:
    print(f"\nint() on 5,000 digits: ValueError: {str(e).split(';')[0]}")


def decode_one_digit(code):
    """Treats every digit as a whole count, so a count of 12 becomes a 1 and then a 2."""
    out = []
    for c in code:
        if c.isdigit():
            out.append(out[-1] * (int(c) - 1))
        else:
            out.append(c)
    return "".join(out)


print(f"\none digit per count: 'a3bc2' -> {decode_one_digit('a3bc2')!r}, 'x12' -> {decode_one_digit('x12')!r}")

Output

'  -0042 kWh'                64-bit:         -42   exact:         -42
'9999999999'                 64-bit:  2147483647   exact:  2147483647
'18446744073709551621 kWh'   64-bit:           5   exact:  2147483647

int() on 5,000 digits: ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 5000 digits

one digit per count: 'a3bc2' -> 'aaabcc', 'x12' -> 'x'

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 direct_attempts.py

What to notice

In problem A, decide the clamp before each digit is added, with a comparison that never leaves the 32-bit range: then the remaining digits cannot matter. In problem B, a count is a number like A’s, accumulated digit by digit. And the encoding of a run is never longer than the run, so the encoded letters can be written over the input as it is read.

Parsing, step by step, with an exact overflow check Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • Why the check is exact, and why a negative overflow returns MIN
    • Edge cases to settle before coding
    • Why Python stops at 4,300 digits
    • The parser in five languages, next to each language’s own parser
  • Run-length decoding with counts of several digits
  • Compressing in place, and why the writer never passes the reader
  • Five parser bugs and one compression bug, reproduced
  • Variants
  • Exercise: readings and runs
    • Parse a meter reading, and decode a run-length code
  • A practice set with sample answers
  • Check yourself
  • Interview questions
    • Write the overflow check of a 32-bit string-to-integer parser that never holds a value outside the int range, and show it is exact at both ends, including −2147483648. Why do many solutions get the negative end wrong?
    • A form sends quantities to three services: a Java service calls Integer.parseInt, a Python job calls int(), and a C++ importer calls atoi. Give inputs on which they disagree, explain each difference, and define one rule that all three should share.
    • Compress a character array in place into runs of a letter and its count, the count left out when it is 1, and prove the writer never overwrites unread input. A new format writes the count even when it is 1: can that still be done in place, and how?
  • Key takeaways

6 runnable examples (C++, Go, Java, JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 20 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.