Java State Machine Solution


  • 1
    B

    I wrote a rather explicit state machine solution. For brevity, I trimmed the input and also used flags so I didn't have to create new classes for different states. Could be much simpler, but I found being explicit was helpful here. For example, my first pass I failed to look for signs or exponents, adding a new state was trivial. I'm not going to spend any more time cleaning it up, runtime was 11 ms.

    public class Solution {
        
        public enum States {
                EMPTY,
                INVALID,
                VALID,
                EXPONENT
        }
        
        public class StateMachine {
            private State state;
            public StateMachine() {
                this.state = new EmptyState(true, true);
            }
            
            private abstract class State {
                public States state;
                public abstract State process(char c);
                public States getState() {
                    return this.state;
                }
            }
            
            private class InvalidState extends State {
                public InvalidState () {
                    super.state = States.INVALID;
                }
                public State process(char c) {
                    return this;
                }
            }
            
            private class ExponentState extends State {
                public ExponentState() {
                    super.state = States.EXPONENT;
                }
                
                public State process(char c) {
                    if(Character.isDigit(c)) {
                        return new ValidState(false, false);
                    }
                    
                    // still in the exponent phase, not quite valid, e.g. e-5 or e+9
                    if(c == '-' || c == '+') {
                        return this;
                    }
                    
                    return new InvalidState();
                }
            }
            
            private class ValidState extends State {
                private boolean allowPeriod, allowExponent;
                public ValidState(boolean allowPeriod, boolean allowExponent) {
                    super.state = States.VALID;
                    this.allowPeriod = allowPeriod;
                    this.allowExponent = allowExponent;
                }
                public State process(char c) {
                    if(Character.isDigit(c)) {
                        return this;
                    }
                    
                    if((c == 'e' || c == 'E') && this.allowExponent) {
                        return new ExponentState();
                    }
                    
                    if(c == '.' && allowPeriod) {
                        return new ValidState(false, this.allowExponent);
                    }
                    
                    return new InvalidState();
                }
            }
            
            private class EmptyState extends State {
                private boolean allowPeriod, allowSign;
                public EmptyState(boolean allowPeriod, boolean allowSign) {
                    super.state = States.EMPTY;
                    this.allowPeriod = allowPeriod;
                    this.allowSign = allowSign;
                }
                
                public State process(char c) {
                    // We haven't seen a period or negative yet and still haven't seen a digit.
                    if(c == ' ' && allowPeriod && allowSign) {
                        return this;
                    }
                    
                    if(Character.isDigit(c)) {
                        return new ValidState(this.allowPeriod, true);
                    }
                    
                    if(c == '.' && allowPeriod) {
                        return new EmptyState(false, false);
                    }
                    
                    // If we get the first sign, continue. If we've seen a period this isn't valid.
                    if((c == '-' || c == '+' ) && allowSign && allowPeriod) {
                        return new EmptyState(true, false);
                    }
                    
                    return new InvalidState();
                }
            }
            
            public void process(char c) {
                States current = state.getState();
                state = state.process(c);
            }
            
            public States getState() {
                return this.state.getState();
            }
        }
        
        
        public boolean isNumber(String s) {
            StateMachine fsm = new StateMachine();
            String trimmedS = s.trim();
            int index = 0;
            while(fsm.getState() != States.INVALID && index < trimmedS.length()) {
                fsm.process(trimmedS.charAt(index));
                index++;
            }
            
            return fsm.getState() == States.VALID;
        }
    }

Log in to reply
 

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