[Is a valid number?] Without isNaN or Regex.


  • 0
    B

    I think the intention of this question is not to use isNaN and Regex. I do not understand why people use it to resolve this problem.

    I just checked many conditions to optimize the speed to avoid unnecessary iteration for the cases that is obviously invalid.

    Refer to the comments in the code for the explanation.

    const allowedChars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', 'e', '.', '+'];
    const numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    
    /**
     * @param {string} s
     * @return {boolean}
     */
    var isNumber = function(str) {
        str = str.trim();
        
        if (str.length === 0) {
            return false;
        }
        
        const oriStr = str;
        const occurenceInfo = getOccurences(oriStr, ['.', 'e', '-', '+']);
        
        // Not allowed char found
        if (occurenceInfo === null) {
            return false;
        }
        
        // exceed the allowed number of occurence for special chars
        if (occurenceInfo['-'].length > 2 || occurenceInfo['e'].length > 1 || occurenceInfo['.'].length > 1 || occurenceInfo['+'].length > 2) {
            return false;
        }
            
        // If no special chars are found, just check if it is an integer
        if (occurenceInfo['+'].length === 0 && occurenceInfo['-'].length === 0 && occurenceInfo['e'].length === 0 && occurenceInfo['.'].length === 0) {
            return isInteger(oriStr);
        }
    
        // This if will take care of the right part from the occurence index of 'e'
        if (occurenceInfo['e'].length) {
            // 'e' can't be located in the last
        	if (occurenceInfo['e'][0] === oriStr.length - 1) {
            	return false;
            }
        
            let rightNumberFromE = oriStr.substring(occurenceInfo['e'][0] + 1, oriStr.length);
            str = oriStr.substr(0, occurenceInfo['e'][0]); // this is the left part of the string from 'e' and will be processed further after this if.
            
            // Right part from 'e' should be an integer
            if (!isInteger(rightNumberFromE)) {
                return false;
            }
            
            // If the left part from 'e' is empty, it is not allowed
            if (str.length === 0) {
                return false;
            }
        }
    
        // From this point, str never has 'e' part.
        if (occurenceInfo['.'].length) {
            let rightNumberFromDot = str.substring(occurenceInfo['.'][0] + 1, str.length);
            let leftNumberFromDot = str.substr(0, occurenceInfo['.'][0]);
            
            // the right part from '.' should be all number regardless of order
            if (!isAllNumber(rightNumberFromDot)) {
                return false;
            }
            
            // get rid of '-' or '+' if it is located in the front
            leftNumberFromDot = leftNumberFromDot[0] === '-' || leftNumberFromDot[0] === '+' ? leftNumberFromDot.substring(1, leftNumberFromDot.length) : leftNumberFromDot;
            
            // There is only a '.', which is invalid
            if (rightNumberFromDot.length === 0 && leftNumberFromDot.length === 0) {
                return false;
            }
            
            // There should be at least a number on the left of '.'
            if (leftNumberFromDot.length === 0) {
            	return true;
            }
                
            // The left part should be an integer
            return isInteger(leftNumberFromDot);
        }
    
        // No 'e', no '.' but '+' or '-' is contained. Just check if it is an integer
        return isInteger(str);
    };
    
    /**
     * @function
     *
     * Return true if the given string has only numbers
     *
     * @param {String} str - string to check
     * @return {Boolean} - Return true if the given string contains only numbers
     */
    function isAllNumber(str) {
        for (let i = 0; i < str.length; i++) {
            if (!~numbers.indexOf(str[i])) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * @function
     *
     * Return true if the given string is an integer. This allows to have + or - in front
     *
     * @param {String} str - string to check
     * @return {Boolean} - Return true if the given string is an integer
     */
    function isInteger(str) {
        str = str[0] === '-' || str[0] === '+' ? str.substr(1, str.length) : str;
        
        if (str.length) {
            for (let i = 0; i < str.length; i++) {
                if (!~numbers.indexOf(str[i])) {
                    return false;
                }
            }
            
            return true;
        }
            
        return false;
    }
            
    /**
     * @function
     *
     * Return occurence information object of the given string and chars array, containing indice information of each char
     *
     * @param {String} str - string to check
     * @param {Array.<String>} chars - Array of char to check the occurence
     * @return {Array.<number>|null} - array of indice of occurent c, null if not allowed charactors are included
     */
    function getOccurences(str, chars) {
        const result = {};
        
        for (let k = 0; k < chars.length; k++) {
            let c = chars[k];
            
            result[c] = [];
            
            for (let i = 0; i < str.length; i++) {
                if (!~allowedChars.indexOf(str[i])) {
                    return null;
                }
                
                if (str[i] === c) {
                    result[c].push(i);
                }
            }
        }
        
        return Object.freeze(result);
    }
    
    

Log in to reply
 

Looks like your connection to LeetCode Discuss was lost, please wait while we try to reconnect.