{x}
blog image

Valid Number

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 '.'.

Solution Explanation: Valid Number

This problem asks to determine if a given string represents a valid number. A valid number can be an integer, a decimal number, or either of these followed by an optional exponent. The solution uses a case-by-case approach with detailed checks to ensure validity.

Approach: Case Discussion and State Machine (Implicit)

The solution efficiently handles various scenarios through a series of checks, essentially functioning as a simple state machine without explicitly defining states. It iterates through the input string, examining each character and updating internal variables to track the number of decimal points and exponents encountered.

The core logic revolves around these points:

  1. Handling Signs: It accounts for optional '+' or '-' signs at the beginning and before the exponent.

  2. Decimal Points: The dot variable counts decimal points. More than one decimal point indicates an invalid number. A decimal point must be followed by at least one digit.

  3. Exponents: The e variable counts exponents ('e' or 'E'). Only one exponent is allowed. An exponent must be followed by an integer.

  4. Digit Checks: The code explicitly verifies if characters are digits. Non-digit characters (other than '+', '-', '.', 'e', 'E') lead to an invalid number.

  5. Boundary Conditions: The code rigorously handles edge cases like empty strings, strings with only signs, and strings ending with an exponent or decimal point.

Time and Space Complexity

  • Time Complexity: O(n), where n is the length of the input string. The solution iterates through the string once.

  • Space Complexity: O(1). The solution uses a constant amount of extra space to store variables (i, dot, e).

Code Explanation (Python3 Example)

The Python code effectively implements the approach:

class Solution:
    def isNumber(self, s: str) -> bool:
        n = len(s)
        i = 0
        # Handle optional +/- sign at the beginning
        if s[i] in '+-':
            i += 1
        if i == n:  # Only sign, invalid
            return False
 
        # Check for invalid leading "."
        if s[i] == '.' and (i + 1 == n or s[i + 1] in 'eE'):
            return False
 
        dot = e = 0  # Counters for decimal points and exponents
        j = i  # Secondary index for iteration
        while j < n:
            if s[j] == '.':
                if e or dot:  # Multiple dots or dot after exponent, invalid
                    return False
                dot += 1
            elif s[j] in 'eE':
                if e or j == i or j == n - 1: # Multiple exponents, or exponent at beginning/end, invalid
                    return False
                e += 1
                # Handle optional +/- before exponent
                if j + 1 < n and s[j + 1] in '+-':
                    j += 1
                    if j == n - 1: # Only sign after 'e', invalid
                        return False
            elif not s[j].isnumeric():  # Invalid character
                return False
            j += 1
        return True

The code in other languages follows a similar structure, adapting syntax and data types according to each language's specifications. The core logic remains consistent. The C# solution uses a regular expression, offering a concise alternative but potentially sacrificing readability for those less familiar with regex.