# Valid Number
**Difficulty:** HARD
[External](https://leetcode.com/problems/valid-number)
Canonical: https://scaleengineer.com/dsa/problems/valid-number
**Data structures:** String
**Companies:** [Amazon](https://scaleengineer.com/companies/amazon), [Apple](https://scaleengineer.com/companies/apple), [Google](https://scaleengineer.com/companies/google), [LinkedIn](https://scaleengineer.com/companies/linkedin), [Meta](https://scaleengineer.com/companies/meta), [Nutanix](https://scaleengineer.com/companies/nutanix), [TikTok](https://scaleengineer.com/companies/tiktok), [Instacart](https://scaleengineer.com/companies/instacart)
---
## Problem
Given a string `s`, return whether `s` is a **valid number**.  
  
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"`.

Formally, a **valid number** is defined using one of the following definitions:

1. An **integer number** followed by an **optional exponent**.
2. A **decimal number** followed by an **optional exponent**.

An **integer number** is defined with an **optional sign** `'-'` or `'+'` followed by **digits**.

A **decimal number** is defined with an **optional sign** `'-'` or `'+'` followed by one of the following definitions:

1. **Digits** followed by a **dot** `'.'`.
2. **Digits** followed by a **dot** `'.'` followed by **digits**.
3. A **dot** `'.'` followed by **digits**.

An **exponent** is defined with an **exponent notation** `'e'` or `'E'` followed by an **integer number**.

The **digits** are defined as one or more digits.

**Example 1:**

**Input:** s = "0"

**Output:** true

**Example 2:**

**Input:** s = "e"

**Output:** false

**Example 3:**

**Input:** s = "."

**Output:** false

**Constraints:**

* `1 <= s.length <= 20`
* `s` consists of only English letters (both uppercase and lowercase), digits (`0-9`), plus `'+'`, minus `'-'`, or dot `'.'`.

# Approaches
## Regular Expression
This approach uses a single regular expression to validate the entire string. Regular expressions provide a powerful and concise way to define and match string patterns, making the code short and declarative.
**Time:** O(N) · **Space:** O(1)
**Pros:** Very concise and often a one-line solution.; Highly readable for developers familiar with regular expressions.; Leverages powerful, optimized, and built-in features of the language.
**Cons:** Regex patterns can be complex to write, read, and debug, especially for intricate rules.; The performance might be slightly slower than a manual parser due to the overhead of the regex engine, although the asymptotic complexity is the same.
### Explanation
A valid number can be broken down into three parts: an optional sign, a number part (mantissa), and an optional exponent part. We can construct a regex that captures all these rules.

- **Overall Structure**: `[sign][mantissa][exponent]`
- **Sign**: `[+-]?` - An optional `+` or `-` at the beginning.
- **Mantissa**: `(\d+(\.\d*)?|\.\d+)` - This is the most complex part. It ensures there's at least one digit. It matches either:
  - `\d+(\.\d*)?`: One or more digits, optionally followed by a dot and zero or more digits. This covers cases like `"2"`, `"2."`, and `"2.3"`.
  - `|`: OR
  - `\.\d+`: A dot followed by one or more digits. This covers cases like `".3"`.
- **Exponent**: `([eE][+-]?\d+)?` - This matches the optional exponent part. It looks for `e` or `E`, followed by an optional sign, and then one or more digits. The `?` at the end makes the whole group optional.

Combining these parts and anchoring them with `^` (start of string) and `$` (end of string) gives the final regex.

```java
class Solution {
    public boolean isNumber(String s) {
        // The regex is constructed to match the formal definition of a valid number.
        // ^[+-]?                # optional sign at the start
        // (
        //   \d+(\.\d*)?      # a number with an optional decimal part (e.g., "2", "2.", "2.5")
        //   |
        //   \.\d+             # a decimal part without an integer part (e.g., ".5")
        // )
        // ([eE][+-]?\d+)?      # an optional exponent part (e.g., "e-10")
        // $
        String regex = "^[+-]?(\\d+(\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?$";
        return s.matches(regex);
    }
}
```
### Algorithm
- The core idea is to construct a single regular expression that encapsulates all the rules for a valid number.
- The regex is built by defining patterns for each component of a valid number: an optional sign, the mantissa (integer or decimal part), and an optional exponent.
- The components are combined, and anchored with `^` and `$` to ensure the entire string must match the pattern.
- The final regex is `^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$`.
- The `String.matches()` method in Java can be used to test the input string against this regex.

## Manual Scan with Flags (State Machine)
This approach involves a single, manual pass through the string, using several boolean flags to keep track of the components of a number that have been encountered (e.g., a digit, a decimal point, an exponent symbol). This method avoids the overhead of a regex engine and provides maximum performance and control.
**Time:** O(N) · **Space:** O(1)
**Pros:** Most performant approach in practice due to direct character processing with no overhead.; Provides fine-grained control over the parsing logic, making it adaptable to complex or unusual rules.; The logic is self-contained and does not depend on any external libraries or complex language features.
**Cons:** The code can be more verbose compared to a regex solution.; The logic with multiple flags and conditions can become complex and prone to errors if edge cases are not handled systematically.
### Explanation
This implementation is a form of a state machine where the flags (`digitSeen`, `dotSeen`, `eSeen`) implicitly define the current state of the parsing process. We scan the string once, character by character, and validate the string's structure on the fly.

The logic ensures that all rules are followed. For instance, a dot `.` cannot appear after an `e` or another dot. An `e` must be preceded by a number and cannot appear more than once. A sign `+` or `-` is only allowed at the very beginning or immediately after an `e`. The final check on `digitSeen` is crucial to validate that the number or exponent part actually contains digits.

```java
class Solution {
    public boolean isNumber(String s) {
        boolean digitSeen = false;
        boolean dotSeen = false;
        boolean eSeen = false;
        int n = s.length();

        for (int i = 0; i < n; i++) {
            char c = s.charAt(i);

            if (Character.isDigit(c)) {
                digitSeen = true;
            } else if (c == '.') {
                if (dotSeen || eSeen) {
                    // A dot cannot appear after another dot or after 'e'
                    return false;
                }
                dotSeen = true;
            } else if (c == 'e' || c == 'E') {
                if (eSeen || !digitSeen) {
                    // 'e' cannot appear after another 'e' or without a preceding number
                    return false;
                }
                eSeen = true;
                digitSeen = false; // Reset digitSeen for the exponent part
            } else if (c == '+' || c == '-') {
                if (i != 0 && s.charAt(i - 1) != 'e' && s.charAt(i - 1) != 'E') {
                    // A sign must be at the start or immediately follow 'e'
                    return false;
                }
            } else {
                // Any other character is invalid
                return false;
            }
        }

        // The string is valid only if a digit was seen in the last component.
        // This handles cases like "1e", ".", "+", "1e+", which are invalid.
        return digitSeen;
    }
}
```
### Algorithm
- Initialize boolean flags `digitSeen`, `dotSeen`, and `eSeen` to `false`.
- Iterate through the string character by character from left to right.
- For each character, apply a set of rules based on the current character and the flags:
  - **Digit**: Set `digitSeen` to `true`.
  - **Dot `.`**: Return `false` if a `dot` or `e` has already been seen. Otherwise, set `dotSeen` to `true`.
  - **Exponent `e` or `E`**: Return `false` if an `e` has already been seen or if no digit has been seen before it. Otherwise, set `eSeen` to `true` and reset `digitSeen` to `false` (to enforce that the exponent part must have digits).
  - **Sign `+` or `-`**: Return `false` if it's not at the beginning of the string and does not immediately follow an `e` or `E`.
  - **Other characters**: Return `false` immediately.
- After the loop finishes, return the final value of `digitSeen`. This final check correctly handles cases like `"1e"`, `"."`, or `"+"`, which are invalid because they lack a required digit part.

# Solutions
### CSharp

```csharp
using System.Text.RegularExpressions ; public class Solution { private readonly Regex _isNumber_Regex = new Regex ( @"^\s*[+-]?(\d+(\.\d*)?|\.\d+)([Ee][+-]?\d+)?\s*$" ); public bool IsNumber ( string s ) { return _isNumber_Regex . IsMatch ( s ); } }
```

### Java

```java
class Solution {
public
  boolean isNumber(String s) {
    int n = s.length();
    int i = 0;
    if (s.charAt(i) == '+' || s.charAt(i) == '-') {
      ++i;
    }
    if (i == n) {
      return false;
    }
    if (s.charAt(i) == '.' &&
        (i + 1 == n || s.charAt(i + 1) == 'e' || s.charAt(i + 1) == 'E')) {
      return false;
    }
    int dot = 0, e = 0;
    for (int j = i; j < n; ++j) {
      if (s.charAt(j) == '.') {
        if (e > 0 || dot > 0) {
          return false;
        }
        ++dot;
      } else if (s.charAt(j) == 'e' || s.charAt(j) == 'E') {
        if (e > 0 || j == i || j == n - 1) {
          return false;
        }
        ++e;
        if (s.charAt(j + 1) == '+' || s.charAt(j + 1) == '-') {
          if (++j == n - 1) {
            return false;
          }
        }
      } else if (s.charAt(j) < '0' || s.charAt(j) > '9') {
        return false;
      }
    }
    return true;
  }
}

```

### CPP

```cpp
class Solution {
public:
  bool isNumber(string s) {
    int n = s.size();
    int i = 0;
    if (s[i] == '+' || s[i] == '-')
      ++i;
    if (i == n)
      return false;
    if (s[i] == '.' && (i + 1 == n || s[i + 1] == 'e' || s[i + 1] == 'E'))
      return false;
    int dot = 0, e = 0;
    for (int j = i; j < n; ++j) {
      if (s[j] == '.') {
        if (e || dot)
          return false;
        ++dot;
      } else if (s[j] == 'e' || s[j] == 'E') {
        if (e || j == i || j == n - 1)
          return false;
        ++e;
        if (s[j + 1] == '+' || s[j + 1] == '-') {
          if (++j == n - 1)
            return false;
        }
      } else if (s[j] < '0' || s[j] > '9')
        return false;
    }
    return true;
  }
};

```

### Python

```python
class Solution:
    def isNumber(self, s: str) -> bool: n = len(s) i = 0 if s[i] in '+-': i += 1 if i == n: return False if s[i] == '.' and (i + 1 == n or s[i + 1] in 'eE'): return False dot = e = 0 j = i while j < n: if s[j] == '.': if e or dot: return False dot += 1 elif s[j] in 'eE': if e or j == i or j == n - 1: return False e += 1 if s[j + 1] in '+-': j += 1 if j == n - 1: return False elif not s[j]. isnumeric(): return False j += 1 return True

```
