Topics › Strings › Medium String Problems
String to Integer (atoi)
LeetCode ↗ Java source ↗ Edit this article ↗
Jump to code:
Problem
Implement the function myAtoi(String s), which converts the leading integer in a string to a 32-bit signed integer the way C’s atoi does:
- Skip any leading spaces (only the character
' '). - Read one optional sign,
'+'or'-'. - Read digits until the first non-digit character or the end of the string. Leading zeros carry no value.
- If no digits were read the result is
0. - If the value lies outside
[-2^31, 2^31 - 1], clamp it to the nearest bound.
Constraints: 0 ≤ |s| ≤ 200; s may contain English letters, digits, spaces, '+', '-' and '.'.
Example 1
s = " -42"
answer = -42 // spaces skipped, sign read, two digits read
Example 2
s = "4193 with words"
answer = 4193 // parsing stops at the first non-digit
Example 3
s = "-91283472332"
answer = -2147483648 // below the int range, so clamped to Integer.MIN_VALUE
Example 4
s = "words and 987"
answer = 0 // the first non-space character is not a sign or digit
The first three steps are the same in every solution, and they are the easy part. The whole difficulty of this problem is step 5: the number may not fit in the type we are building it in, and we have to notice that before it wraps around.
Approach 1: Accumulate in a long and clamp as soon as the range is left
Intuition. The natural way to build a number from digits is result = result * 10 + digit. The danger is overflow: int wraps silently, so 2147483648 would turn into a negative number. Using a long accumulator gives nine extra decimal digits of headroom, and if we compare sign * result against the int bounds after every digit we return the clamped value the moment the number steps out of range. Because we stop at the first excess digit, the long itself never gets anywhere near its own limit, even for an input like "99999999999999999999999".
Algorithm.
- Advance
ipast leading' 'characters. - If
s[i]is'+'or'-', recordsignand advance. - While
s[i]is a digit:result = result * 10 + digit; ifsign * result > MAXreturnMAX; ifsign * result < MINreturnMIN; advance. - Return
(int) (sign * result).
static int usingLong(String s) {
int i = 0, n = s.length();
while (i < n && s.charAt(i) == ' ') i++; // 1. leading spaces (only ' ')
int sign = 1;
if (i < n && (s.charAt(i) == '+' || s.charAt(i) == '-')) { // 2. one optional sign
if (s.charAt(i) == '-') sign = -1;
i++;
}
long result = 0;
while (i < n && s.charAt(i) >= '0' && s.charAt(i) <= '9') { // 3. digits until the first non-digit
result = result * 10 + (s.charAt(i) - '0');
if (sign * result > Integer.MAX_VALUE) return Integer.MAX_VALUE; // 4. clamp as soon as we overflow
if (sign * result < Integer.MIN_VALUE) return Integer.MIN_VALUE;
i++;
}
return (int) (sign * result);
}
Complexity. Time O(n): one pass. Space O(1).
The check must be inside the loop. Checking only once after the loop is a common bug: a string with twenty or more digits overflows a long just as surely as ten digits overflow an int.
Approach 2: Optimal, int only, test before multiplying
Intuition. We can avoid long entirely by asking, before we append a digit, whether result * 10 + digit would exceed Integer.MAX_VALUE. Rearranging that inequality gives a test that cannot itself overflow: result > (MAX - digit) / 10. Here is why the integer division is exact. Let q = (MAX - digit) / 10 rounded down. If result ≤ q then result * 10 + digit ≤ 10q + digit ≤ (MAX - digit) + digit = MAX, so appending is safe. If result ≥ q + 1 then result * 10 ≥ 10q + 10 > MAX - digit, so appending overflows. The test is therefore an exact “would it overflow” oracle using only int arithmetic on values that are all in range.
What about negative numbers? The most negative int is MIN = -(MAX + 1), so the magnitude of a negative result may be one larger than MAX. Our test clamps whenever the magnitude would exceed MAX, that is, whenever it would be at least MAX + 1. The only magnitude in that range that is actually representable is exactly MAX + 1, and clamping returns MIN, which is the correct answer for it. So one test serves both signs.
Algorithm.
- Skip spaces and read the optional sign exactly as before.
- For each digit: if
result > (MAX - digit) / 10, returnMAXfor a positive sign orMINfor a negative one; otherwiseresult = result * 10 + digit. - Return
sign * result.
static int optimal(String s) {
int i = 0, n = s.length();
while (i < n && s.charAt(i) == ' ') i++;
int sign = 1;
if (i < n && (s.charAt(i) == '+' || s.charAt(i) == '-')) {
if (s.charAt(i) == '-') sign = -1;
i++;
}
int result = 0;
while (i < n && s.charAt(i) >= '0' && s.charAt(i) <= '9') {
int digit = s.charAt(i) - '0';
// result * 10 + digit > MAX <=> result > (MAX - digit) / 10, and MIN = -(MAX + 1) so the same test clamps negatives
if (result > (Integer.MAX_VALUE - digit) / 10) {
return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
result = result * 10 + digit;
i++;
}
return sign * result;
}
Dry run on s = " -42":
| step | i | character | action | result |
|---|---|---|---|---|
| skip spaces | 0..2 | ' ' |
advance | 0 |
| sign | 3 | '-' |
sign = -1 | 0 |
| digit | 4 | '4' |
0 > (MAX - 4) / 10? no; result = 4 | 4 |
| digit | 5 | '2' |
4 > (MAX - 2) / 10? no; result = 42 | 42 |
| end | 6 | return -1 × 42 | -42 |
Complexity. Time O(n), space O(1). This is the version to write when the interviewer asks you not to use a wider type.
Approach 3: The same parse written recursively
Intuition. The digit loop is a fold: each step takes the magnitude accumulated so far and one more character. A fold can be written as a recursive function that processes one digit and calls itself for the rest. This is how the recursion-focused rows of the sheet expect it, and it is worth seeing that the clamping logic transfers unchanged.
Algorithm.
- Skip spaces and read the sign iteratively (these steps have nothing to recurse over).
- Call
parseDigits(s, i, sign, 0). parseDigitsreturnssign * accifs[i]is not a digit; otherwise it computesnext = acc * 10 + digit, clamps ifnextis out of range for the given sign, and recurses withi + 1andnext.
static int recursive(String s) {
int i = 0, n = s.length();
while (i < n && s.charAt(i) == ' ') i++;
int sign = 1;
if (i < n && (s.charAt(i) == '+' || s.charAt(i) == '-')) {
if (s.charAt(i) == '-') sign = -1;
i++;
}
return parseDigits(s, i, sign, 0);
}
private static int parseDigits(String s, int i, int sign, long acc) {
if (i == s.length() || s.charAt(i) < '0' || s.charAt(i) > '9') return (int) (sign * acc);
long next = acc * 10 + (s.charAt(i) - '0');
if (sign == 1 && next > Integer.MAX_VALUE) return Integer.MAX_VALUE;
if (sign == -1 && -next < Integer.MIN_VALUE) return Integer.MIN_VALUE;
return parseDigits(s, i + 1, sign, next);
}
Complexity. Time O(n). Space O(d) for the call stack, where d ≤ 200 is the number of digits read; the recursion is tail-recursive in shape, but Java does not eliminate tail calls, so the frames are really allocated.
Edge cases and pitfalls
- Empty string or only spaces. The loops do not run and the result is
0. - A sign with no digits.
"-"and"+"return0. - Two signs.
"+-12"returns0: after consuming'+'the next character is'-', which is not a digit, so parsing stops. - Leading zeros.
" 0000000000012345678"returns12345678. The zeros keepresultat0and never trigger the overflow test. - Digits after a break.
"00000-42a1234"returns0, because the'-'after the zeros ends the number. Only the leading integer counts. - Only
' 'is whitespace."\t42"returns0. Do not useCharacter.isWhitespaceortrim(), which skip tabs and newlines too. - The exact boundaries.
"2147483647"is returned unchanged,"2147483648"clamps toMAX,"-2147483648"is representable and returned exactly,"-2147483649"clamps toMIN. - Decimal point.
"3.14159"returns3; the'.'is just a non-digit. - Do not reach for
Integer.parseInt. It throws on"4193 with words"instead of stopping at the space, and it throws on overflow instead of clamping.
Related problems
- Roman to Integer is the previous problem on the sheet, another character-by-character conversion to a number, without the overflow concerns.
- Implement ATOI/STRSTR is the SDE-sheet formulation of this problem.
- Recursive Implementation of atoi() asks specifically for the recursive form shown in Approach 3.
- Reverse a number builds a number digit by digit in the same way and has the same overflow trap.