1
\$\begingroup\$

I was doing following question on leetcode: String to Integer (atoi)

Question:

Implement atoi which converts a string to an integer.

The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.

The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.

If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.

If no valid conversion could be performed, a zero value is returned.

Note:

Only the space character ' ' is considered as whitespace character. Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. If the numerical value is out of the range of representable values, INT_MAX (231 − 1) or INT_MIN (−231) is returned.

Question link: https://leetcode.com/problems/string-to-integer-atoi/

For the above question, I wrote the following code

/**
 * @param {string} str
 * @return {number}
 */
var myAtoi = function(str) {
    let i = 0
    let output = '' 
    const intMax = 2**31 - 1
    const intMin = -intMax - 1
    while (i<str.length) {
       const char = str[i]
       if (!char == " ") {
           if (char.toLowerCase() === char.toUpperCase()) {
               output = output + char
           } else if (output) {
               break
           }
           if (!output) return 0
       }
        i++
    }
    output = parseInt(output)
    if (output !== null && !isNaN(output)) {
        if (output > intMax) return  intMax
        if (output < intMin) return intMin 
        return output
    }
    return 0
}

Can someone improve upon the same and give me suggestions on how I can improve my code?

\$\endgroup\$
  • 1
    \$\begingroup\$ Are you sure you Are allowed to use parseInt? It Is basically atoi function... It defeats the purpose of the excercise if you use native implementation of your task... \$\endgroup\$ – slepic Nov 19 '19 at 11:27
  • 1
    \$\begingroup\$ Also you cannot check if number representation Is greater than the maximum representable number. Because if IT was than the number you Are checking against Is not the greatest representable number. Which Is an obvious contradiction... \$\endgroup\$ – slepic Nov 19 '19 at 11:30
  • \$\begingroup\$ FWIW the original condition doesn't say the environment can't process larger numbers outside of the specified range, it can't store them, which may make sense if the target is a database (or a record in memory) with fixed field types. Overall the question is open for interpretation, it's not really strict. \$\endgroup\$ – wOxxOm Nov 19 '19 at 12:03
7
\$\begingroup\$

Unfortunately there are several problems with your code. It only reason it works is because you are using parseInt which (as @wOxxOm shows) fulfills the original task requirements and thus ignores your broken attempts at cleaning the string.

!char == " "

This expression always returns true. Like in most programming languages negation (!) have a higher precedence than the comparison ==, so !char is resolved to false (unless char were an empty string, which in this case it never is) and false == " " resolves to true (to be honest I'm not sure why, I'd have to look it up. JavaScript's rules for non-strict comparison (==) are quite complex.)

So it should be char != " " , or even better char !== " ". Always use strict comparison, unless you have a good reason not to.

char.toLowerCase() === char.toUpperCase()

This is a strange attempt to identify digits (and +/-). There are countless other characters that are not filtered by this.

32-bit signed integer range

You are missing the point of this rule. When the system is assumed not to be able to store integers outside the range, then that means a variable can't hold such a large/low number, so a comparison such as output > intMax can never be true, since output can't physically contain a number larger than intMax.

Don't reuse variables

In output = parseInt(output) you change the type and the semantics of the variable output. This is confusing for the reader. And the name output for the original use of collecting the validated string wrong anyway.

Don't leave out semicolons

JavaScript's automatic semicolon insertion is nearly as complex as its non-strict comparison rules. By leaving out the semicolons you make the code more difficult to read because the reader then has an additional thing they need to consider.

Finally

The big problem here is you using parseInt. For one, as mentioned it's hiding the bugs in the code, and more importantly, you are missing the whole point of this exercise, which is to understand how string to number conversion actually works.

\$\endgroup\$
0
\$\begingroup\$

If you are allowed to use parseInt and other built-in JS methods there's no need to skip the whitespace in a loop nor to find the sign/digits as parseInt does so by default. Here's the entire code of the function:

// only ACSII spaces are allowed at the start but parseInt also skips tabs and CR/LF
str = str.replace(/^ +/, '');
const num = /^[-+]?\d/.test(str) ? parseInt(str, 10) : 0;
return Math.max(-(2**31), Math.min(2**31 - 1, num || 0));

The || 0 will handle NaN.
Note, parseInt doesn't produce null so you don't need that check.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.