LeetCode 118 - Valid Number | Darren's Blog


Validate if a given string is numeric.
Some examples:
"0" => true
" 0.1 " => true
"abc" => false
"1 a" => false
"2e10" => true
http://www.jiuzhang.com/solutions/valid-number/
    public boolean isNumber(String s) {
        int len = s.length();
        int i = 0, e = len - 1;
        while (i <= e && Character.isWhitespace(s.charAt(i))) i++;
        if (i > len - 1) return false;
        while (e >= i && Character.isWhitespace(s.charAt(e))) e--;
        // skip leading +/-
        if (s.charAt(i) == '+' || s.charAt(i) == '-') i++;
        boolean num = false; // is a digit
        boolean dot = false; // is a '.'
        boolean exp = false; // is a 'e'
        while (i <= e) {
            char c = s.charAt(i);
            if (Character.isDigit(c)) {
                num = true;
            }
            else if (c == '.') {
                if(exp || dot) return false;
                dot = true;
            }
            else if (c == 'e') {
                if(exp || num == false) return false;
                exp = true;
                num = false;
            }
            else if (c == '+' || c == '-') {
                if (s.charAt(i - 1) != 'e') return false;
            }
            else {
                return false;
            }
            i++;
        }
        return num;
    }
https://discuss.leetcode.com/topic/9490/clear-java-solution-with-ifs
All we need is to have a couple of flags so we can process the string in linear time:
We start with trimming.
  • If we see [0-9] we reset the number flags.
  • We can only see . if we didn't see e or ..
  • We can only see e if we didn't see e but we did see a number. We reset numberAfterE flag.
  • We can only see + and - in the beginning and after an e
  • any other character break the validation.
At the and it is only valid if there was at least 1 number and if we did see an e then a number after it as well.
So basically the number should match this regular expression:
[-+]?[0-9]*(.[0-9]+)?(e[-+]?[0-9]+)?
numberAfterE seems to be redundent
Yeah, I guess I could reset numberSeen, and not use numberAfterE all together. Thanks for the suggestion!
public boolean isNumber(String s) {
    s = s.trim();
    
    boolean pointSeen = false;
    boolean eSeen = false;
    boolean numberSeen = false;
    boolean numberAfterE = true;
    for(int i=0; i<s.length(); i++) {
        if('0' <= s.charAt(i) && s.charAt(i) <= '9') {
            numberSeen = true;
            numberAfterE = true;
        } else if(s.charAt(i) == '.') {
            if(eSeen || pointSeen) {
                return false;
            }
            pointSeen = true;
        } else if(s.charAt(i) == 'e') {
            if(eSeen || !numberSeen) {
                return false;
            }
            numberAfterE = false;
            eSeen = true;
        } else if(s.charAt(i) == '-' || s.charAt(i) == '+') {
            if(i != 0 && s.charAt(i-1) != 'e') {
                return false;
            }
        } else {
            return false;
        }
    }
    
    return numberSeen && numberAfterE;
}
https://leetcodenotes.wordpress.com/2013/11/23/leetcode-valid-number/
public boolean isNumber(String s) {
    s = s.trim(); 
    if (s.length() > 0 && s.charAt(s.length() - 1) == 'e')
        return false; //avoid "3e" which is false
    String[] t = s.split("e");
    if (t.length == 0 || t.length > 2)
        return false;
    boolean res = valid(t[0], false);
    if (t.length > 1)
        res = res && valid(t[1], true);
    return res;
}
private boolean valid(String s, boolean hasDot) { // how about change to canHaveDot,  valid(t[0], true),  valid(t[1], false)

    if (s.length() > 0 && (s.charAt(0) == '+' || s.charAt(0) == '-')) //avoid "1+", "+", "+."
    s = s.substring(1);
    char[] arr = s.toCharArray();
    if (arr.length == 0 || s.equals("."))
        return false;
    for (int i = 0; i < arr.length; i++) {
        if (arr[i] == '.') {
            if (hasDot)
                return false;
            hasDot = true;
        } else if (!('0' <= arr[i] && arr[i] <= '9')) {
            return false;
        }
    }
    return true;
}
public boolean isNumber(String s) {
        s = s.trim();       // Get rid of leading and trailing whitespaces
        int n = s.length();
        if (n == 0)
            return false;
        boolean isFractional = false;   // Indicate appearance of '.'
        boolean isExponential = false;  // Indicate appearance of 'e/E'
        boolean valid = false;          // Indicate whether preceding digits are valid
        boolean expoBefore = false;     // Indicate whether the preceding digit is 'e/E'
        boolean validFrac = true;       // Indicate whether the number is a vaild fraction (true by default)
        boolean validExpo = true;       // Indicate whether the number is a valid exponential (true by default)
        int i = 0;
        if (s.charAt(0) == '+' || s.charAt(0) == '-')   // Consider sign
            i = 1;
        // Process each digit in sequence
        for (; i < n; i++) {
            char c = s.charAt(i);
            if (c == '+' || c == '-') {     // +/- is valid only after e/E
                if (!expoBefore)
                    return false;
                expoBefore = false;
                valid = false;
            } else if (c == 'e' || c == 'E') {  // Only one e/E is valid; preceding digits should be valid
                if (isExponential || !valid)
                    return false;
                isExponential = true;
                valid = false;
                expoBefore = true;
                validExpo = false;
            } else if (c == '.') {  // Only one '.' is valid; cannot appear as an exponential
                if (isFractional || isExponential)
                    return false;
                isFractional = true;
                if (!valid)     // Must have fractional part
                    validFrac = false;
            } else if (c >= '0' && c <='9') {   // Regular digits
                valid = true;
                expoBefore = false;
                validFrac = true;
                validExpo = true;
            } else {
                return false;
            }
        }
        // After reaching the end, make sure the number is indeed valid
        if (!valid || !validFrac || !validExpo)
            return false;
        else
            return true;
    }
https://discuss.leetcode.com/topic/8029/a-clean-design-solution-by-using-design-pattern

Use DFA(Deterministic Finite Automata)
Code from http://jelices.blogspot.com/2013/12/leetcode-valid-number.html
We accept the following regular grammar, shown as UNIX regular expression by simplicity:
\s*[\+\-]?(([0-9]+(\.[0-9]*)?)|\.[0-9]+)([eE][+-]?[0-9]+)?\s*
where \s represents [ \t].

This regular expression is accepted by the underneath DFA(Deterministic Finite Automata):
public boolean isNumber(String s) 
    {
        int state = 0;
        for(int i=0; i<s.length();i++)
        {
            state=getNextState(state, s.charAt(i));
            if (state==-1)
                return false;
        }
        state = getNextState(state, ' ');
        return state == 8;
    }
    
    private int getNextState(int state, char c)
    {
        int[][] transitionTable = { {0,2,1,3,-1,-1},
                                    {-1,2,-1,3,-1,-1},
                                    {8,2,-1,4,5,-1},
                                    {-1,4,-1,-1,-1,-1},
                                    {8,4,-1,-1,5,-1},
                                    {-1,7,6,-1,-1,-1},
                                    {-1,7,-1,-1,-1,-1},
                                    {8,7,-1,-1,-1,-1},
                                    {8,-1,-1,-1,-1,-1}};
        return transitionTable[state][getSymbol(c)];
    }
    
    private int getSymbol(char c)
    {
        switch(c)
        {
            case ' ': case '\t': return 0;
            case '0': case '1': case '2':case '3': case '4': case '5': case '6': case '7': case '8': case '9': return 1;
            case '+': case '-': return 2;
            case '.': return 3;
            case 'E': case 'e': return 4;
            default: return 5;
        }
    }
http://noalgo.info/995.html
此题使用一般的判断非常繁琐,极其容易出错,但是可以使用有限状态机进行解决,思路较为直接,而且代码非常简短。
考虑所有可能的输入,不同的输入会导致状态的不同转移,把每种输入用一个数字进行表示如下:
  • 0:非法字符
  • 1:空格
  • 2:正负号
  • 3:小数点
  • 4:指数e
  • 5:数字
令状态S0为初始状态,考虑其在不同输入下的转移情况。
  • 0:数字带有非法字符,非法。转入非法状态,用状态-1表示。
  • 1:数字带有前导空格,合法。新状态和初始状态一样,转入状态0。
  • 2:数字带有正负号,合法。此时需要进入一个新的状态,用状态1表示(内容仅含正负号)。
  • 3:数字一开始即为小数点,合法,因为有如.1之类的数字。需要转入一个新的状态,用状态2表示(内容仅含小数点)。
  • 4:数字一开始即为指数e,非法。转入非法状态-1。
  • 5:数字一开始即为数字,合法。需要转入新状态,用状态3表示(内容仅含数字)。
为了方便,只需要考虑所有合法的转移即可,下面是状态0的含义及转移情况。状态0为初始状态,可以有空格。
  • 1->0:输入空格,转入自身。
  • 2->1:输入正负号,转入新状态1(仅含正负号)。
  • 3->2:输入小数点,转入新状态2(仅含小数点)。
  • 5->3:输入数字,转入新状态3(仅含数字)。
下面考虑状态1。状态1仅含有一个正负号,后面只允许接小数点或者数字。
  • 3->2:接小数点,新状态变为正负号+小数点,可以和状态2合并,转入新状态2([正负号] + 小数点)。
  • 5->3:接数字,新状态变为正负号+数字,可以和状态3合并,转入新状态3([正负号] + 数字)。
下面考虑状态2。状态2包含一个小数点,前面可能含有正负号,[正负号] + 小数点。此时后面只允许接数字。
  • 5->4:接数字,转入新状态4([正负号] + 小数点 + 数字)。
下面考虑状态3。状态3包含数字,前面可能有正负号,[正负号] + 数字。此时后面只允许接空格、小数点、指数e或者数字。
  • 1->4:接空格,转入新状态5(合法数字 + 空格)。
  • 3->4:接小数点,此时状态为数字加小数点,由于形如3.的数字也是合法数字,可以转入状态4([正负号] + 数字 + 小数点)。
  • 4->6:接指数e,转入新状态6,(不带e的合法数字 + e)。
  • 5->3:接数字,转入自身。
下面考虑状态4。状态4为[正负号] + 小数点 + 数字,或者[正负号] + 数字 + 小数点,本质上是一个合法的不带e的数字。其后面可以继续接数字,也可以接空格,指数e。
  • 1->5:接空格,转入状态5。
  • 4->6:接指数e,转入状态6。
  • 5->4:接数字,转入自身。
下面考虑状态5。状态5为一个合法数字接空格,为后导空格情况,此时只允许出现空格字符。
  • 1->5:接空格,转入自身。
下面考虑状态6。状态6为一个不带e的合法数字接e的情况,此时后面只允许出现正负号或者数字。
  • 2->7:接正负,转入新状态7(不带e的合法数字 + e + 正负号)。
  • 5->8:接数字,转入新状态8(不带e的合法数字 + e + 数字)。
下面考虑状态7。状态7为 不带e的合法数字 + e + 正负号,此时后面只允许接数字。
  • 5->8:接数字,转入状态8,状态8变为 不带e的合法数字 + e + [正负号] + 数字
下面考虑状态8:。状态8为 不带e的合法数字 + e + [正负号] + 数字,其后面只能够接数字,或者空格。
  • 1->5:接空格,转入状态5。
  • 5->8:接数字,转入自身。
此时,所有的状态已经考虑完毕,可以得到以下状态转换矩阵trans:
-1,  0,  1,  2, -1,  3
-1, -1, -1,  2, -1,  3
-1, -1, -1, -1, -1,  4
-1,  5, -1,  4,  6,  3
-1,  5, -1, -1,  6,  4
-1,  5, -1, -1, -1, -1
-1, -1,  7, -1, -1,  8
-1, -1, -1, -1, -1,  8
-1,  5, -1, -1, -1,  8
其中trans[i][j]即表示从状态i接受输入j进入的新状态。
还有最后一个问题,自动机中的哪些状态是合法的呢?根据合法数字的定义可以容易知道,状态3、4、5、8是合法状态。
现在可以轻松得到程序的代码了。
    bool isNumber(const char *s) {
        enum InputType {
            INVALID, SPACE, SIGN, DOT, E, DIGIT, LEN
        };
        int trans[][LEN] = {
            {-1,  0,  1,  2, -1,  3},
            {-1, -1, -1,  2, -1,  3},
            {-1, -1, -1, -1, -1,  4},
            {-1,  5, -1,  4,  6,  3},
            {-1,  5, -1, -1,  6,  4},
            {-1,  5, -1, -1, -1, -1},
            {-1, -1,  7, -1, -1,  8},
            {-1, -1, -1, -1, -1,  8},
            {-1,  5, -1, -1, -1,  8}
        };
        int state = 0;
        while (*s) {
            InputType input;
            if (isspace(*s)) {
                input = SPACE;
            } else if (*s == '+' || *s == '-') {
                input = SIGN;
            } else if (*s == '.') {
                input = DOT;
            } else if (*s == 'e' || *s == 'E') {
                input = E;
            } else if (isdigit(*s)) {
                input = DIGIT;
            } else {
                input = INVALID;
            }
            state = trans[state][input];
            if (state == -1) {
                return false;
            }
            s++;
        }
        return state == 3 || state == 4 || state == 5 || state == 8;
    }
http://noalgo.info/993.html
判断一个字符串是否是一个合法的数字。这题非常繁琐,需要考虑的细节非常多,这里罗列如下:
  • 字符串是否为NULL。
  • 数字不能有非法字符。
  • 数字可能带有前导空格和最后面的空格,中间不能有空格。
  • 数字可能带有显示的+号或者-号,但又不能只有正负号。
  • 数字可能带有小数点,但只能有一个小数点,小数点后至少要有一个数字。
  • 数字可能带有e表示10的幂次,e后至少有一个数字,但该数字可以带正负号,但又不能只有正负号。
  • 数字不能同时有e和小数点。

    bool isNumber(const char *s) {
        if (!s) return false;
        while (isspace(*s)) s++;         //前导空格
        if (*s == '+' || *s == '-') s++; //正负号
        if (!*s) return false;
        
        bool hase = false, hasdot = false;
        const char *olds = s;
        for (; *s; s++)
        {
            if (isdigit(*s)) continue;
            else if (*s == '.')
            {
                if (hase || hasdot) return false; //同时有.和e
                if (s == olds && !isdigit(*(s+1))) return false; //至少有一个小数部位
                hasdot = true;
            }
            else if (*s == 'e')
            {
                if (hase || s == olds) return false; //同时又.和e
                s++;
                if (*s == '+' || *s == '-') s++;//正负号
                if (!isdigit(*s)) return false; //至少一个数字表示次方
                hase = true;
            }
            else if (isspace(*s))
            {
                while (*s) if (!isspace(*s++)) return false; //后续全为空格
                return true;
            }
            else //非法字符
                return false;
        }
        return true;
    }
Use Regular Expression:
Code from http://www.cnblogs.com/midnightcat/p/3364431.html
Pattern p = Pattern.compile("^[\\+\\-]?((\\d+(\\.\\d*)?)|(\\.\\d+))(e[\\+\\-]?\\d+)?$");
    public boolean isNumber(String s) {
        String ss = s.trim();
        return p.matcher(ss).matches();
    }
Also refer to http://blog.csdn.net/ithomer/article/details/8832300
http://blog.csdn.net/kenden23/article/details/18696083
Read full article from LeetCode - Valid Number | Darren's Blog

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts