Problem: Valid Number

A valid number can be split up into these components (in order):

1. A decimal number or an integer.
2. (Optional) An `'e'` or `'E'`, followed by an integer.

A decimal number can be split up into these components (in order):

1. (Optional) A sign character (either `'+'` or `'-'`).
2. One of the following formats: 
1. One or more digits, followed by a dot `'.'`.
2. One or more digits, followed by a dot `'.'`, followed by one or more digits.
3. A dot `'.'`, followed by one or more digits.

An integer can be split up into these components (in order):

1. (Optional) A sign character (either `'+'` or `'-'`).
2. One or more digits.

For example, all the following are valid numbers: `["2", "0089", "-0.1",
"+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93",
"-123.456e789"]`, while the following are not valid numbers: `["abc", "1a",
"1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]`.

Given a string `s`, return `true` if `s` is a valid number.


Python solution:
import math
import itertools
import bisect
import collections
import string
import heapq
import functools
import sortedcontainers
from typing import List, Dict, Tuple, Iterator

class Solution:
  def isNumber(self, s: str) -> bool:
    s = s.strip()
    if not s:
      return False

    seenNum = False
    seenDot = False
    seenE = False

    for i, c in enumerate(s):
      if c == '.':
        if seenDot or seenE:
          return False
        seenDot = True
      elif c == 'e' or c == 'E':
        if seenE or not seenNum:
          return False
        seenE = True
        seenNum = False
      elif c in '+-':
        if i > 0 and s[i - 1] not in 'eE':
          return False
        seenNum = False
      else:
        if not c.isdigit():
          return False
        seenNum = True

    return seenNum


Java solution:
class Solution {
  public boolean isNumber(String s) {
    s = s.trim();
    if (s.isEmpty())
      return false;

    boolean seenNum = false;
    boolean seenDot = false;
    boolean seenE = false;

    for (int i = 0; i < s.length(); ++i) {
      switch (s.charAt(i)) {
        case '.':
          if (seenDot || seenE)
            return false;
          seenDot = true;
          break;
        case 'e':
        case 'E':
          if (seenE || !seenNum)
            return false;
          seenE = true;
          seenNum = false;
          break;
        case '+':
        case '-':
          if (i > 0 && s.charAt(i - 1) != 'e' && s.charAt(i - 1) != 'E')
            return false;
          seenNum = false;
          break;
        default:
          if (!Character.isDigit(s.charAt(i)))
            return false;
          seenNum = true;
      }
    }

    return seenNum;
  }
}


C++ solution:
class Solution {
 public:
  bool isNumber(string s) {
    trim(s);
    if (s.empty())
      return false;

    bool seenNum = false;
    bool seenDot = false;
    bool seenE = false;

    for (int i = 0; i < s.length(); ++i) {
      switch (s[i]) {
        case '.':
          if (seenDot || seenE)
            return false;
          seenDot = true;
          break;
        case 'e':
        case 'E':
          if (seenE || !seenNum)
            return false;
          seenE = true;
          seenNum = false;
          break;
        case '+':
        case '-':
          if (i > 0 && s[i - 1] != 'e' && s[i - 1] != 'E')
            return false;
          seenNum = false;
          break;
        default:
          if (!isdigit(s[i]))
            return false;
          seenNum = true;
      }
    }

    return seenNum;
  }

 private:
  void trim(string& s) {
    s.erase(0, s.find_first_not_of(' '));
    s.erase(s.find_last_not_of(' ') + 1);
  }
};