A clear java solution with custom string iterator


  • 0
    A
    public class Solution
    {
        /** A helper class for iterating over string characters (more like a queue) */
        private static class StringIterator
        {
            private final String str;
            private int index;
    
            public StringIterator(String str)
            {
                this.str = str;
                this.index = -1;
            }
    
            /** True, if the next character is one of the characters from the string */
            public boolean checkNext(String chars)
            {
                return hasNext() && chars.indexOf(peek()) != -1;
            }
    
            /** True, if the next character is one of the characters from the string + skip it */
            public boolean skipNext(String chars)
            {
                if (checkNext(chars))
                {
                    next();
                    return true;
                }
                return false;
            }
    
            /** Has more characters */
            public boolean hasNext()
            {
                return index + 1 < str.length();
            }
    
            /** Check the next character without removing it */
            public char peek()
            {
                return str.charAt(index + 1);
            }
    
            /** Remove and return next character */
            public char next()
            {
                return str.charAt(++index);
            }
    
            /** Number of available characters */
            public int available()
            {
                return str.length() - (index + 1);
            }
        }
    
        private enum DigitBase
        {
            Dec,     // decimal
            Hex,     // hexadecimal
        }
    
        public boolean isNumber(String s)
        {
            s = s.trim();
    
            if (s.length() == 0) return false;
    
            StringIterator iter = new StringIterator(s);
    
            // check sign
            if (iter.skipNext("+-") && !iter.hasNext()) return false;
    
            // if only one char is available - it should be a digit
            if (iter.available() == 1) return isValidDigit(iter.next(), DigitBase.Dec);
    
            DigitBase digitBase = DigitBase.Dec; // decimal by default
    
            boolean hasIntegerPart = false;
            boolean hasFracPart = false;
    
            // check next numbers
            if (iter.skipNext("0"))
            {
                // simple zero
                if (!iter.hasNext()) return true;
    
                if (iter.skipNext("xX"))
                {
                    if (!iter.hasNext()) return true;
                    digitBase = DigitBase.Hex;
                }
                else
                {
                    hasIntegerPart = true;
                }
            }
    
            boolean hasDecimalPoint = false;
            boolean hasExponent = false;
    
            // check chars one by one
            while (iter.hasNext())
            {
                char c = iter.next();
    
                if (c == ' ')
                {
                    return false; // can't have any spaces
                }
                else if (c == '.')
                {
                    // can only have a single decimal point and no exponent yet
                    if (hasDecimalPoint || hasExponent || digitBase != DigitBase.Dec) return false;
    
                    hasDecimalPoint = true;
                }
                else if (isValidDigit(c, digitBase)) // valid character for the selected base
                {
                    if (hasDecimalPoint)
                    {
                        hasFracPart = true; // if decimal point was found - then we have a fracture part
                    }
                    else if (!hasExponent)
                    {
                        hasIntegerPart = true; // if exponent was not found - we have an integer part
                    }
                }
                else if (oneOf(c, "eE")) // found exponent?
                {
                    if (!iter.hasNext()) return false; // if no character after - invalid number
    
                    // we should have a single exponent and at least either an integer or a fracture part
                    if (hasExponent || !hasIntegerPart && !hasFracPart) return false;
    
                    hasExponent = true;
    
                    // an optional +/- sign
                    if (iter.skipNext("-+") && !iter.hasNext()) return false;
    
                    digitBase = DigitBase.Dec; // HACK: only expect decimal digits
                }
                else
                {
                    return false; // something unexpected
                }
            }
    
            return true; // all good!
        }
    
        /** Is a valid digit for the selected base */
        private boolean isValidDigit(char c, DigitBase digitBase)
        {
            switch (digitBase)
            {
                case Hex: return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F';
            }
            return c >= '0' && c <= '9';
        }
    
        /** True is char is one of the characters from the string */
        private boolean oneOf(char c, String chars)
        {
            return chars.indexOf(c) != -1;
        }
    }
    

Log in to reply
 

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