Bird
Raised Fist0
DSA Typescriptprogramming~15 mins

String to Integer atoi in DSA Typescript - Deep Dive

Choose your learning style10 modes available
Overview - String to Integer atoi
What is it?
Implement the atoi (ASCII to integer) function that converts a string to a 32-bit signed integer. The algorithm must handle leading whitespace, optional sign (+/-), digit extraction, invalid characters, and integer overflow/underflow clamped to [INT32_MIN, INT32_MAX] = [-2147483648, 2147483647]. This is a careful string parsing problem with multiple edge cases.
Why it matters
atoi tests systematic input validation — a skill used in parsing user input, API responses, configuration files, and protocol implementations. It also highlights a TypeScript/JavaScript-specific challenge: JS numbers are 64-bit floats that handle large values without overflow, but the problem requires simulating 32-bit integer overflow behavior explicitly.
Where it fits
You need comfort with TypeScript string methods (.trim(), character code access), type coercion, and 32-bit integer bounds before tackling this. After mastering it, valid number parsing, Roman to integer, and expression evaluation follow naturally.
Mental Model
Core Idea
Process the string left-to-right through four sequential phases: skip whitespace → read sign → read digits → clamp to 32-bit bounds. Stop as soon as a non-digit (after sign) is encountered.
Think of it like...
Reading a number written on a receipt: first skip any leading spaces, note if it says 'minus' or 'plus', then read digits until you hit a letter or end of receipt. If the number is too big for your calculator's display, show the maximum it can hold.
Input:  '   -42abc'

Phase 1: Skip whitespace → '   ' skipped, index=3
Phase 2: Read sign     → '-', sign=-1, index=4
Phase 3: Read digits   → '4','2' → result=42, stop at 'a'
Phase 4: Apply sign    → -1 × 42 = -42
Phase 5: Clamp         → -42 is within [-2147483648, 2147483647]
Output: -42
Build-Up - 5 Steps
1
FoundationThe Four Phases
🤔
Concept: atoi processes input in four sequential phases: whitespace → sign → digits → clamp.
Phase 1: Skip all leading whitespace (s[i] === ' '). Phase 2: Read optional sign ('+' or '-'). Phase 3: Read consecutive digits until non-digit or end of string. Convert digit characters to numbers: digit = s.charCodeAt(i) - '0'.charCodeAt(0). Build result: result = result * 10 + digit. Phase 4: Apply sign and clamp to [INT32_MIN, INT32_MAX]. Stop immediately when a non-digit appears after the sign — don't skip further.
Result
Systematic left-to-right parsing with clear phase transitions.
The phases are sequential, not interleaved. Implementing them in order prevents edge case confusion.
2
FoundationTypeScript String to Digit — charCodeAt vs parseInt
🤔
Concept: Use charCodeAt(i) - '0'.charCodeAt(0) for safe digit extraction.
Two approaches in TypeScript: (1) const digit = s.charCodeAt(i) - 48 (ASCII code of '0' is 48). This directly converts a digit character to its numeric value. (2) parseInt(s[i], 10) — works but slower and can return NaN for non-digits requiring extra checking. The charCodeAt approach combined with a range check (code >= 48 && code <= 57) is both efficient and explicit.
Result
charCodeAt-based digit extraction is the idiomatic TypeScript/JavaScript approach for single-digit parsing.
Using '0'.charCodeAt(0) instead of the magic number 48 is more readable and self-documenting. TypeScript's strict mode enforces consistent use.
3
Intermediate32-bit Integer Overflow — TypeScript's Challenge
🤔Before reading on: can a JavaScript number overflow a 64-bit float? What is 2^53? Commit to your answer.
Concept: JavaScript numbers are 64-bit floats — they don't naturally overflow at 32-bit bounds. We must explicitly clamp.
JavaScript (and TypeScript) uses IEEE 754 double-precision floats. These can represent integers exactly up to 2^53. So 2147483648 (just above INT32_MAX) is representable without error — there's no automatic overflow. We must manually check after each digit: if (result > 2147483647) return sign === -1 ? -2147483648 : 2147483647. Check BEFORE multiplying to avoid exceeding Number.MAX_SAFE_INTEGER on extremely long digit strings.
Result
Explicit clamping after each digit addition prevents both incorrect results and potential floating-point precision loss.
The overflow check must happen before the multiply-and-add step: if (result > Math.floor((2147483647 - digit) / 10)) — this pre-checks whether adding the next digit would overflow.
4
IntermediateEdge Cases — Systematic Coverage
🤔Before reading on: list all edge cases you can think of for atoi. Commit your list.
Concept: All edge cases can be derived from the four phases — one for each phase.
Whitespace only: ' ' → return 0 (no digits after whitespace). No digits after sign: '+' or '-' only → return 0. Leading zeros: '007' → 7 (reading naturally handles this). Multiple signs: '+-3' → 0 (only read ONE sign; '+' is not a digit so we stop). Overflow: '99999999999' → 2147483647 (clamp). Negative overflow: '-99999999999' → -2147483648. Mixed: '3.14159' → 3 (stop at '.'). Letters first: 'abc123' → 0 (stop immediately, no digits read).
Result
Systematic edge case coverage from the phase model.
The phase model makes edge cases obvious: each edge case is a boundary condition of one of the four phases.
5
AdvancedUsing TypeScript's Built-ins — Temptations and Traps
🤔Before reading on: does parseInt('3.14159') return 3 or 3.14159 in TypeScript? Commit to your answer.
Concept: parseInt and parseFloat exist but don't match atoi's exact behavior — implement from scratch.
parseInt('3.14159') returns 3 in JavaScript/TypeScript — it stops at the decimal point. parseInt(' -42abc') returns -42. So parseInt handles some cases correctly, but: (1) it doesn't clamp to 32-bit bounds — parseInt('99999999999') returns 99999999999, not 2147483647. (2) it handles '0x' hex prefix, which atoi does not. (3) Interviews want the manual implementation, not parseInt. Using parseInt as a shortcut will fail on overflow test cases.
Result
Always implement atoi manually — parseInt is close but doesn't handle 32-bit clamping.
Knowing parseInt's behavior and its differences from atoi demonstrates deep TypeScript/JS knowledge — mention this comparison in interviews as a bonus insight.
Under the Hood
The algorithm is a simple linear scan O(n) where n is string length. The key implementation detail is the overflow check: rather than checking after overflow occurs (which might exceed Number.MAX_SAFE_INTEGER), check BEFORE the next digit would push us over INT32_MAX. The standard check: if (result > Math.floor(2147483647 / 10) || (result === Math.floor(2147483647 / 10) && digit > 7)) — this handles both the multiply-overflow and the add-overflow cases.
Why designed this way?
atoi's specification (from C's stdlib) was designed for character-by-character sequential parsing — no lookahead needed. The TypeScript implementation follows the same sequential pattern, adapted for TypeScript's string API and explicit 32-bit clamping instead of C's undefined overflow behavior.
Input: '  -2147483649'

i=0,1: skip spaces
i=2: '-' → sign=-1, i=3
i=3: '2' → result=2
i=4: '1' → result=21
i=5: '4' → result=214
i=6: '7' → result=2147
i=7: '4' → result=21474
i=8: '8' → result=214748
i=9: '3' → result=2147483
i=10: '6' → result > 214748364 → OVERFLOW CHECK
      sign=-1 → clamp to INT32_MIN = -2147483648
Return: -2147483648
Myth Busters - 3 Common Misconceptions
Quick: does JavaScript number overflow at INT32_MAX (2147483647)? Commit yes or no.
Common Belief:JavaScript numbers overflow at 32-bit integer bounds automatically.
Tap to reveal reality
Reality:JavaScript numbers are 64-bit floats. They don't overflow at 32-bit bounds. atoi must explicitly check and clamp to [-2147483648, 2147483647].
Why it matters:Without explicit clamping, '99999999999' returns 99999999999 instead of 2147483647 — failing all overflow test cases.
Quick: does parseInt in TypeScript correctly implement atoi? Commit yes or no.
Common Belief:parseInt(' -42abc') === myAtoi(' -42abc') so parseInt solves atoi.
Tap to reveal reality
Reality:parseInt matches atoi for most inputs but NOT for overflow cases. parseInt('99999999999') returns 99999999999; atoi should return 2147483647.
Why it matters:Using parseInt as a shortcut fails overflow test cases — the most important edge cases in atoi interviews.
Quick: should '+-12' return -12 or 0? Commit your answer.
Common Belief:'+' and '-' together means negative — return -12.
Tap to reveal reality
Reality:Only one sign is allowed. After reading '+', the next character '-' is not a digit, so parsing stops. '+-12' returns 0 (no valid digits read).
Why it matters:This edge case reveals whether the candidate reads sign then immediately starts digit parsing, or continues scanning for more signs.
Expert Zone
1
The overflow check before multiply: if (result > Math.floor(2147483647 / 10)) is safer than checking after, since JavaScript can represent numbers well above INT32_MAX without precision loss.
2
For the boundary case result === 214748364 (INT32_MAX / 10), we must also check the digit: digit > 7 for positive overflow, digit > 8 for negative overflow (since -2147483648 ends in 8).
3
TypeScript's Number.MAX_SAFE_INTEGER (2^53 - 1) is far larger than INT32_MAX — no precision issues arise unless the input string has more than ~15 digits, which is well beyond any valid 32-bit integer.
When NOT to use
If you need to parse large integers beyond 32-bit bounds, use BigInt in TypeScript. If parsing a formatted number string with decimals, use parseFloat with clamping. atoi's specific behavior (stop at first non-digit, clamp to 32-bit) is exactly what the leetcode problem specifies.
Production Patterns
The atoi pattern appears in: CLI argument parsing, HTTP header value parsing (Content-Length, status codes), CSV numeric field extraction, and configuration file readers. All require the same four-phase approach: skip noise, read sign, read digits, validate range.
Connections
Valid Number (LeetCode)
Both are string parsing problems — Valid Number is more complex (allows decimals, scientific notation) but uses the same character-by-character scan approach.
atoi is the simplest case of numeric string validation. Mastering its phase structure prepares you for the more complex Valid Number problem.
TypeScript Number Types and BigInt
atoi explicitly handles 32-bit clamping in a language whose native number type is 64-bit float — reinforcing the importance of understanding TypeScript's numeric representation.
TypeScript 3.2+ introduced BigInt for arbitrary precision integers. For atoi, we don't need BigInt — 64-bit float handles all intermediate values safely. But knowing when to use BigInt vs number is an important TypeScript skill.
Common Pitfalls
#1Using parseInt and missing overflow clamping.
Wrong approach:function myAtoi(s: string): number { return parseInt(s.trim()) || 0; // WRONG: no 32-bit clamping }
Correct approach:// Must manually implement with explicit clamp: const INT32_MAX = 2147483647; const INT32_MIN = -2147483648; if (result > INT32_MAX) return sign === 1 ? INT32_MAX : INT32_MIN; return sign * result;
Root cause:parseInt returns a 64-bit JavaScript number — it doesn't clamp to 32-bit bounds. The overflow test cases will fail.
#2Checking overflow after the multiply instead of before.
Wrong approach:result = result * 10 + digit; if (result > 2147483647) return sign === 1 ? 2147483647 : -2147483648; // WRONG: overflow may lose precision
Correct approach:// Check BEFORE multiplying: if (result > Math.floor(2147483647 / 10)) { return sign === 1 ? 2147483647 : -2147483648; } result = result * 10 + digit;
Root cause:Checking after the multiply is safe in JavaScript (64-bit float handles it), but the best practice is pre-check — it mirrors the C implementation and avoids any potential precision issues with very long digit strings.
#3Not stopping at the first non-digit after the sign.
Wrong approach:for (const ch of s) { if (ch >= '0' && ch <= '9') result = result * 10 + Number(ch); // WRONG: skips non-digits and continues reading }
Correct approach:while (i < s.length && s[i] >= '0' && s[i] <= '9') { result = result * 10 + s.charCodeAt(i) - 48; i++; } // Correct: breaks immediately on first non-digit
Root cause:atoi stops at the first non-digit character — it does not skip non-digits and continue. '12abc34' returns 12, not 1234.
Key Takeaways
Four phases in order: skip whitespace → read sign → read digits (stop at first non-digit) → clamp to [INT32_MIN, INT32_MAX].
JavaScript/TypeScript numbers are 64-bit floats — they do NOT overflow at 32-bit bounds. Must manually clamp to [-2147483648, 2147483647].
Do NOT use parseInt — it doesn't clamp to 32-bit bounds and will fail overflow test cases.
Use charCodeAt(i) - 48 for efficient digit extraction; pair with range check (charCode >= 48 && charCode <= 57).
Overflow pre-check: if result > Math.floor(2147483647 / 10) before the multiply step.

Practice

(1/5)
1. What does the atoi function do when given a string input?
easy
A. Converts the string to a floating-point number
B. Reverses the string characters
C. Converts the string to an integer number
D. Counts the number of characters in the string

Solution

  1. Step 1: Understand the purpose of atoi

    The atoi function stands for ASCII to integer and converts a string representing a number into an integer value.
  2. Step 2: Compare options with function behavior

    Only Converts the string to an integer number correctly describes this conversion. Other options describe different operations unrelated to atoi.
  3. Final Answer:

    Converts the string to an integer number -> Option C
  4. Quick Check:

    atoi converts string to integer [OK]
Hint: Remember atoi means ASCII to integer conversion [OK]
Common Mistakes:
  • Thinking atoi converts to float
  • Confusing atoi with string reversal
  • Assuming atoi counts characters
2. Which of the following TypeScript function signatures correctly represents a simple atoi function?
easy
A. function atoi(str: string): number
B. function atoi(num: number): string
C. function atoi(str: number): string
D. function atoi(): void

Solution

  1. Step 1: Identify input and output types for atoi

    atoi takes a string input and returns a number (integer).
  2. Step 2: Match function signature with correct types

    function atoi(str: string): number matches this: input is string, output is number. Other options have wrong input/output types or no parameters.
  3. Final Answer:

    function atoi(str: string): number -> Option A
  4. Quick Check:

    Input string, output number [OK]
Hint: atoi input is string, output is number [OK]
Common Mistakes:
  • Swapping input and output types
  • Using no parameters
  • Using wrong parameter types
3. What is the output of the following TypeScript code?
function atoi(str: string): number {
  let i = 0, num = 0, sign = 1;
  while (str[i] === ' ') i++;
  if (str[i] === '-' || str[i] === '+') {
    sign = str[i] === '-' ? -1 : 1;
    i++;
  }
  while (i < str.length && str[i] >= '0' && str[i] <= '9') {
    num = num * 10 + (str.charCodeAt(i) - 48);
    i++;
  }
  return num * sign;
}
console.log(atoi("  -42abc"));
medium
A. -42
B. 42
C. 0
D. NaN

Solution

  1. Step 1: Skip leading spaces and detect sign

    The code skips spaces, finds '-', so sign = -1, index moves past '-'.
  2. Step 2: Parse digits until non-digit

    Reads '4' and '2', converts to number 42, stops at 'a'.
  3. Step 3: Apply sign and return

    Returns 42 * -1 = -42.
  4. Final Answer:

    -42 -> Option A
  5. Quick Check:

    Parsed number with sign = -42 [OK]
Hint: Skip spaces, check sign, parse digits until non-digit [OK]
Common Mistakes:
  • Not skipping spaces
  • Ignoring sign character
  • Parsing non-digit characters
4. The following TypeScript atoi implementation has a bug. What is the bug?
function atoi(str: string): number {
  let num = 0;
  let i = 0;
  while (i < str.length && str[i] === ' ') i++;
  for (; i < str.length; i++) {
    if (str[i] < '0' || str[i] > '9') break;
    num = num * 10 + (str.charCodeAt(i) - 48);
  }
  return num;
}
medium
A. Returns string instead of number
B. Does not handle leading spaces
C. Does not stop parsing at non-digit characters
D. Does not handle negative or positive signs

Solution

  1. Step 1: Check for sign handling

    The code does not check for '+' or '-' signs before parsing digits.
  2. Step 2: Verify other behaviors

    It skips leading spaces, stops parsing at first non-digit and returns number, so no issue there. The main bug is missing sign handling.
  3. Final Answer:

    Does not handle negative or positive signs -> Option D
  4. Quick Check:

    Missing sign handling in atoi [OK]
Hint: Check if signs '+' or '-' are handled [OK]
Common Mistakes:
  • Assuming spaces are main bug
  • Thinking it parses non-digit characters
  • Confusing return type
5. You want to extend the atoi function to handle integer overflow by clamping the result between INT_MIN = -2147483648 and INT_MAX = 2147483647. Which code snippet correctly clamps the value before returning?
const INT_MIN = -2147483648;
const INT_MAX = 2147483647;

function atoi(str: string): number {
  let i = 0, num = 0, sign = 1;
  while (str[i] === ' ') i++;
  if (str[i] === '-' || str[i] === '+') {
    sign = str[i] === '-' ? -1 : 1;
    i++;
  }
  while (i < str.length && str[i] >= '0' && str[i] <= '9') {
    num = num * 10 + (str.charCodeAt(i) - 48);
    i++;
  }
  num = num * sign;
  // Clamp here
  // ???
  return num;
}
hard
A. if (num > INT_MIN) return INT_MIN; if (num < INT_MAX) return INT_MAX;
B. if (num < INT_MIN) return INT_MIN; if (num > INT_MAX) return INT_MAX;
C. if (num < INT_MAX) return INT_MIN; if (num > INT_MIN) return INT_MAX;
D. if (num === INT_MIN) return INT_MAX; if (num === INT_MAX) return INT_MIN;

Solution

  1. Step 1: Understand clamping logic

    If number is less than INT_MIN, return INT_MIN; if greater than INT_MAX, return INT_MAX.
  2. Step 2: Match correct condition and return

    if (num < INT_MIN) return INT_MIN; if (num > INT_MAX) return INT_MAX; correctly checks and returns clamped values. Other options have incorrect comparisons or swap min/max.
  3. Final Answer:

    if (num < INT_MIN) return INT_MIN; if (num > INT_MAX) return INT_MAX; -> Option B
  4. Quick Check:

    Clamp below min and above max correctly [OK]
Hint: Clamp with if less than min or greater than max [OK]
Common Mistakes:
  • Swapping INT_MIN and INT_MAX in conditions
  • Using equality instead of inequality
  • Returning wrong clamp value
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard