065

difficulty: Hard

Validate if a given string can be interpreted as a decimal number.

Some examples: "0" => true " 0.1 " => true "abc" => false "1 a" => false "2e10" => true " -90e3 " => true " 1e" => false "e3" => false " 6e-1" => true " 99e2.5 " => false "53.5e93" => true " --6 " => false "-+3" => false "95a54e53" => false

Note: It is intended for the problem statement to be ambiguous. You should gather all requirements up front before implementing one. However, here is a list of characters that can be in a valid decimal number:

  • Numbers 0-9

  • Exponent - "e"

  • Positive/negative sign - "+"/"-"

  • Decimal point - "."

Of course, the context of these characters also matters in the input.

Update (2015-02-10): The signature of the C++ function had been updated. If you still see your function signature accepts a const char * argument, please click the reload button to reset your code definition.

Method One

class Solution {
    public boolean isNumber(String s) {
        //这个问题需要讨论的是四个符号如何合法。
        // e 和. 都只能出现一次。
        // e 的合法是需要 e 前后都有合法数字。
        // 并且 e 之前可以出现小数点,e之后只能是纯数字和首位正负号
        // . 的合法是,只能出现在e之前,并且小数点前或者后面至少有数字
        // + - 的合法是只能出现在字符最开始和 e 之后, 因此我们需要index的信息
        // 这个字符串被e分成了两部分,当e出现之后进行第二次检查。
        s = s.trim();
        boolean decimalSeen = false;
        boolean eSeen = false;
        boolean numberSeen = false;
        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            if( c <= '9' && c >= '0'){
                numberSeen = true;
            }else if( c == 'e') {
                if(!numberSeen || eSeen) {
                    return false;
                }
                eSeen = true;
                numberSeen = false;
            }else if ( c == '.'){
                if(eSeen || decimalSeen){
                    return false;
                }
                decimalSeen = true;
            }else if( c == '+' || c == '-'){
                // !(i == 0 || s.charAt(i - 1 ) != 'e')
            }else if( c == '+' || c == '-'){
                if( i != 0 && s.charAt(i - 1) != 'e'){
                    return false;
                }
            }else {
                return false;
            }
        }
        return numberSeen;
    }
}

上面的代码写的有点不太易懂,我们需要把算法搞清楚,下面的可读性会强一点。

class Solution {
    // 学英语 一个小数 decimal number
    // 整数部分 integer part, 小数部分 decimal part
    public boolean isNumber(String s) {
        /**
        // 先由e或者E分成两部分
        // e 或者 E, PartA, E之前是个小数,PartB, E 之后是个整数
        // partB: 整数的字符的要求,除了第一位可以是 + -, 别的必须是数字,而且不能只是一个 + -
        // partA: 
                小数的要求,只能第一个字符是 + -,所以我们先检查第一位,之后就不允许出现+-了
                dot 最多出现一次
                0 - 9 至少出现一次,即不能是 empty number
                进入 partB 之前,立刻检查partA是不是合法的 
        */

        if (s.length() == 0) return false;

        Queue<Character> charQueue = new ArrayDeque<>();
        for ( char c : s.toCharArray() ) {
            charQueue.offer(c);
        }
        // 先检查符号
        if (charQueue.peek() == '+' || charQueue.peek() == '-') {
            charQueue.poll();
        }
        if (charQueue.isEmpty()) return false;

        boolean hasDecimal = false;
        boolean isEmptyNumber = true;
        // 现在我们只关心 . 数字 和 e,别的字符都不允许
        // . 最多出现一次
        // 数字至少出现一次
        // e出现了之后 我们立刻检查前面是不是满足了 数字至少出现一次
        while (!charQueue.isEmpty()) {
            char c = charQueue.poll();
            if (c == '.') {
                if (hasDecimal) return false;
                hasDecimal = true;
                continue;
            }
            if (c == 'e' || c == 'E') {
                if (isEmptyNumber) return false;
                return isInteger(charQueue);
            }
            if (!Character.isDigit(c)) {
                return false;
            }
            isEmptyNumber = false;
        }
        return !isEmptyNumber;
    }

    // isInteger 用来检测 partB 是不是一个整数
    private boolean isInteger(Queue<Character> charQueue) {
        if (charQueue.isEmpty()) return false;
        if (charQueue.peek() == '+' || charQueue.peek() == '-') {
            charQueue.poll();
        }
        if (charQueue.isEmpty()) return false;

        while (!charQueue.isEmpty()) {
            if (!Character.isDigit(charQueue.poll())) {
                return false;
            }
        }
        return true;
    }
}

Last updated

Was this helpful?