8. String to Integer (atoi)
Problem Description
The problem asks you to implement a function myAtoi(string s)
that converts a string to a 32-bit signed integer, similar to C/C++'s atoi
function.
The conversion follows these specific rules:
-
Skip leading whitespace: Any spaces at the beginning of the string should be ignored.
-
Determine the sign: After skipping whitespace, check if the next character is
'-'
or'+'
. If it's'-'
, the number will be negative. If it's'+'
or neither sign is present, the number will be positive. -
Read digits: Convert consecutive digit characters into an integer. Skip any leading zeros and stop reading when you encounter a non-digit character or reach the end of the string. If no valid digits are found, return
0
. -
Handle overflow: The result must be within the range of a 32-bit signed integer
[-2^31, 2^31 - 1]
, which is[-2147483648, 2147483647]
. If the number would overflow:- Numbers less than
-2^31
should return-2147483648
- Numbers greater than
2^31 - 1
should return2147483647
- Numbers less than
For example:
- Input:
"42"
→ Output:42
- Input:
" -42"
→ Output:-42
(leading spaces are ignored) - Input:
"4193 with words"
→ Output:4193
(reading stops at the first non-digit) - Input:
"words and 987"
→ Output:0
(first non-whitespace character is not a digit or sign) - Input:
"-91283472332"
→ Output:-2147483648
(the number underflows the 32-bit range)
The solution needs to carefully handle edge cases like empty strings, strings with only spaces, and integer overflow situations during the conversion process.
Intuition
The key insight is to process the string character by character in a single pass, following the exact order of operations specified in the problem. We need to handle the conversion step-by-step like a state machine.
First, we recognize that we need to skip whitespaces until we find a meaningful character. This is straightforward - just keep moving our pointer forward while we see spaces.
For the sign detection, we only need to check once after skipping whitespaces. If we see a '-'
or '+'
, we record it and move forward. The trick here is to use a sign variable that's either 1
or -1
, which we can multiply with our final result.
The core challenge is building the integer while checking for overflow. The natural approach would be to build the number as result = result * 10 + digit
, but we need to check for overflow before this operation happens, not after (since after might already cause overflow in our program).
To check for overflow preemptively, we observe that the maximum 32-bit integer is 2147483647
. If our current result is greater than 214748364
(which is (2^31 - 1) // 10
), then multiplying by 10 would definitely overflow. If our result equals 214748364
, then we need to check if the next digit is greater than 7
(the last digit of 2147483647
). This way, we can detect overflow before it actually happens.
The beauty of this approach is that we handle both positive and negative overflow with the same logic - we just return the appropriate boundary value based on the sign we detected earlier. This eliminates the need for separate overflow checking logic for positive and negative numbers.
By processing the string in a single linear scan and stopping as soon as we hit a non-digit character, we achieve an efficient O(n)
solution that handles all edge cases elegantly.
Solution Approach
The implementation follows a linear traversal approach, processing the string character by character from left to right.
Step 1: Handle edge cases
First, check if the string is empty or has zero length. If so, return 0
immediately as there's nothing to convert.
Step 2: Skip leading whitespaces
Use an index pointer i
starting at 0
and increment it while s[i]
is a space character. If we reach the end of the string (all characters were spaces), return 0
.
Step 3: Determine the sign
Check if the character at position i
is '-'
or '+'
. Store the sign as -1
for negative or 1
for positive. If a sign character is found, increment i
to move past it.
sign = -1 if s[i] == '-' else 1 if s[i] in ['-', '+']: i += 1
Step 4: Convert digits with overflow checking
Initialize the result as 0
and calculate the overflow threshold as flag = (2**31 - 1) // 10
, which equals 214748364
.
While traversing the remaining characters:
- If the current character is not a digit, break the loop
- Convert the character to an integer:
c = int(s[i])
- Check for overflow before adding the digit:
- If
res > flag
, multiplying by 10 will definitely overflow - If
res == flag
andc > 7
, adding this digit will overflow (since2147483647
ends with7
) - If overflow is detected, return
2**31 - 1
for positive or-(2**31)
for negative numbers
- If
- If no overflow, update the result:
res = res * 10 + c
- Move to the next character:
i += 1
Step 5: Return the final result
Multiply the accumulated result by the sign and return it: sign * res
The clever part of this solution is the preemptive overflow check. By comparing against (2**31 - 1) // 10
and checking the last digit separately when equal, we avoid actual integer overflow in our calculation. This ensures the algorithm works correctly even in languages with fixed integer sizes.
The time complexity is O(n)
where n
is the length of the string, as we traverse it at most once. The space complexity is O(1)
as we only use a few variables regardless of input size.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the example " -42"
to illustrate the solution approach:
Initial state:
- String:
" -42"
- Index
i = 0
- Result
res = 0
Step 1: Skip leading whitespaces
s[0] = ' '
→ incrementi
to1
s[1] = ' '
→ incrementi
to2
s[2] = ' '
→ incrementi
to3
s[3] = '-'
→ not a space, stop
Step 2: Determine the sign
s[3] = '-'
→ setsign = -1
- Since we found a sign character, increment
i
to4
Step 3: Convert digits with overflow checking
- Set overflow threshold:
flag = 214748364
First digit:
s[4] = '4'
→ it's a digit- Check overflow:
res = 0
which is less thanflag
, so no overflow - Update:
res = 0 * 10 + 4 = 4
- Increment
i
to5
Second digit:
s[5] = '2'
→ it's a digit- Check overflow:
res = 4
which is less thanflag
, so no overflow - Update:
res = 4 * 10 + 2 = 42
- Increment
i
to6
End of string:
i = 6
equals string length, exit loop
Step 4: Return the result
- Final result:
sign * res = -1 * 42 = -42
Let's also trace through an overflow example "-91283472332"
:
After skipping whitespace and handling sign:
sign = -1
,i = 1
,res = 0
Converting digits:
'9'
:res = 9
'1'
:res = 91
'2'
:res = 912
'8'
:res = 9128
'3'
:res = 91283
'4'
:res = 912834
'7'
:res = 9128347
'2'
:res = 91283472
'3'
:res = 912834723
'3'
: Nowres = 912834723
>flag = 214748364
- Overflow detected! Since
sign = -1
, return-2147483648
- Overflow detected! Since
Solution Implementation
1class Solution:
2 def myAtoi(self, s: str) -> int:
3 # Handle empty string
4 if not s:
5 return 0
6
7 n = len(s)
8 index = 0
9
10 # Skip leading whitespaces
11 while index < n and s[index] == ' ':
12 index += 1
13
14 # Check if string contains only whitespaces
15 if index == n:
16 return 0
17
18 # Determine sign of the number
19 sign = -1 if s[index] == '-' else 1
20
21 # Move past sign character if present
22 if s[index] in ['-', '+']:
23 index += 1
24
25 # Initialize result and overflow threshold
26 result = 0
27 # Maximum value that result can be before multiplying by 10
28 # (2^31 - 1) // 10 = 214748364
29 overflow_threshold = (2**31 - 1) // 10
30
31 # Process digits
32 while index < n:
33 # Stop if current character is not a digit
34 if not s[index].isdigit():
35 break
36
37 current_digit = int(s[index])
38
39 # Check for overflow before updating result
40 # If result > overflow_threshold, multiplying by 10 will overflow
41 # If result == overflow_threshold and current_digit > 7,
42 # then result * 10 + current_digit > 2^31 - 1 (2147483647)
43 if result > overflow_threshold or (result == overflow_threshold and current_digit > 7):
44 # Return INT_MAX or INT_MIN based on sign
45 return 2**31 - 1 if sign > 0 else -(2**31)
46
47 # Update result
48 result = result * 10 + current_digit
49 index += 1
50
51 # Apply sign and return final result
52 return sign * result
53
1class Solution {
2 public int myAtoi(String s) {
3 // Handle null input
4 if (s == null) return 0;
5
6 int length = s.length();
7 // Handle empty string
8 if (length == 0) return 0;
9
10 // Skip leading whitespaces
11 int index = 0;
12 while (index < length && s.charAt(index) == ' ') {
13 index++;
14 }
15
16 // Check if string contains only spaces
17 if (index == length) return 0;
18
19 // Determine the sign of the number
20 int sign = 1;
21 if (s.charAt(index) == '-') {
22 sign = -1;
23 }
24
25 // Move past the sign character if present
26 if (s.charAt(index) == '-' || s.charAt(index) == '+') {
27 index++;
28 }
29
30 // Build the result number
31 int result = 0;
32 int overflowThreshold = Integer.MAX_VALUE / 10;
33
34 // Process digits
35 while (index < length) {
36 char currentChar = s.charAt(index);
37
38 // Stop if non-digit character is encountered
39 if (currentChar < '0' || currentChar > '9') {
40 break;
41 }
42
43 // Check for overflow before adding the next digit
44 // For positive: result > 214748364 or (result == 214748364 and digit > 7)
45 // For negative: result > 214748364 or (result == 214748364 and digit > 8)
46 // Since we check with '7', this works for both cases due to sign multiplication
47 if (result > overflowThreshold ||
48 (result == overflowThreshold && currentChar > '7')) {
49 return sign > 0 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
50 }
51
52 // Append current digit to result
53 result = result * 10 + (currentChar - '0');
54 index++;
55 }
56
57 // Apply sign and return final result
58 return sign * result;
59 }
60}
61
1class Solution {
2public:
3 int myAtoi(string s) {
4 int index = 0;
5 int length = s.size();
6
7 // Step 1: Skip leading whitespaces
8 while (index < length && s[index] == ' ') {
9 ++index;
10 }
11
12 // Step 2: Check for sign character
13 int sign = 1; // Default to positive
14 if (index < length && (s[index] == '-' || s[index] == '+')) {
15 sign = (s[index] == '-') ? -1 : 1;
16 ++index;
17 }
18
19 // Step 3: Convert digits to integer
20 int result = 0;
21 while (index < length && isdigit(s[index])) {
22 int digit = s[index] - '0';
23
24 // Step 4: Check for overflow/underflow before multiplication
25 // If result > INT_MAX / 10, then result * 10 would overflow
26 // If result == INT_MAX / 10, check if adding digit would overflow
27 if (result > INT_MAX / 10 ||
28 (result == INT_MAX / 10 && digit > INT_MAX % 10)) {
29 // Return INT_MAX for positive overflow, INT_MIN for negative overflow
30 return (sign == 1) ? INT_MAX : INT_MIN;
31 }
32
33 // Update result with current digit
34 result = result * 10 + digit;
35 ++index;
36 }
37
38 // Step 5: Apply sign and return final result
39 return result * sign;
40 }
41};
42
1/**
2 * Converts a string to a 32-bit signed integer (similar to C/C++ atoi function)
3 * @param str - The input string to be converted
4 * @returns The converted integer, clamped to 32-bit signed integer range
5 */
6const myAtoi = function (str: string): number {
7 // Remove leading and trailing whitespace
8 str = str.trim();
9
10 // Return 0 for empty string
11 if (!str) return 0;
12
13 // Track sign of the number (1 for positive, 0 for negative)
14 let isPositive: number = 1;
15 let index: number = 0;
16 let result: number = 0;
17
18 // Check for explicit sign character
19 if (str[index] === '+') {
20 isPositive = 1;
21 index++;
22 } else if (str[index] === '-') {
23 isPositive = 0;
24 index++;
25 }
26
27 // Process digits
28 for (; index < str.length; index++) {
29 // Convert character to digit (ASCII '0' is 48)
30 const digit: number = str.charCodeAt(index) - 48;
31
32 // Stop if character is not a digit
33 if (digit > 9 || digit < 0) break;
34
35 // Check for overflow before updating result
36 // INT_MAX = 2147483647, INT_MIN = -2147483648
37 if (result > 2147483647 / 10 || result > (2147483647 - digit) / 10) {
38 return isPositive ? 2147483647 : -2147483648;
39 } else {
40 result = result * 10 + digit;
41 }
42 }
43
44 // Return result with appropriate sign
45 return isPositive ? result : -result;
46};
47
Time and Space Complexity
Time Complexity: O(n)
, where n
is the length of the input string s
. The algorithm iterates through the string at most once. Specifically:
- The first while loop skips leading whitespaces - at most
n
iterations - The second while loop processes digits - at most
n
iterations - Each character is visited at most once, and all operations within the loops (comparison, digit conversion, arithmetic operations) take constant time
O(1)
- Therefore, the overall time complexity is linear with respect to the input string length
Space Complexity: O(1)
. The algorithm uses only a constant amount of extra space regardless of the input size:
- Variables
i
,n
,sign
,res
,flag
, andc
are all primitive types that occupy constant space - No additional data structures (arrays, lists, etc.) are created that scale with the input size
- The space used remains constant throughout the execution
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Overflow Detection Timing
One of the most common mistakes is checking for overflow after performing the multiplication and addition operations, rather than before:
Incorrect approach:
result = result * 10 + current_digit if result > 2**31 - 1: # Too late! Overflow may have already occurred return 2**31 - 1 if sign > 0 else -(2**31)
Why it fails: In languages with fixed integer sizes, the multiplication result * 10 + current_digit
might already cause an overflow before you can check it, leading to undefined behavior or incorrect wraparound values.
Correct approach: Check for potential overflow before the operation:
if result > overflow_threshold or (result == overflow_threshold and current_digit > 7): return 2**31 - 1 if sign > 0 else -(2**31) result = result * 10 + current_digit
2. Forgetting the Edge Case for Negative Overflow
Another pitfall is incorrectly handling the asymmetry between positive and negative 32-bit integer limits. The range is [-2^31, 2^31 - 1]
, meaning the minimum value (-2147483648
) has a larger absolute value than the maximum (2147483647
).
Incorrect approach:
if result > overflow_threshold or (result == overflow_threshold and current_digit > 7): return 2**31 - 1 # Always returns MAX_INT, ignoring sign
Correct approach: Consider the sign when returning overflow values:
if result > overflow_threshold or (result == overflow_threshold and current_digit > 7): return 2**31 - 1 if sign > 0 else -(2**31)
3. Not Handling Multiple Sign Characters
A subtle pitfall is not properly moving past the sign character, which could lead to returning 0 when encountering strings like "+123"
:
Incorrect approach:
sign = -1 if s[index] == '-' else 1 # Forgot to increment index past the sign character!
Correct approach:
sign = -1 if s[index] == '-' else 1 if s[index] in ['-', '+']: index += 1 # Move past the sign character
4. Using String Slicing Instead of Index Tracking
While tempting, using string slicing operations can lead to unnecessary string copies and potential index errors:
Inefficient approach:
s = s.strip() # Creates a new string if s[0] == '-': sign = -1 s = s[1:] # Another string copy
Better approach: Use index tracking to avoid creating new strings:
while index < n and s[index] == ' ': index += 1
These pitfalls highlight the importance of careful boundary checking, proper overflow handling, and efficient string traversal when implementing the atoi
function.
How does quick sort divide the problem into subproblems?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!