Alkesh

LeetCode - Valid Number

Problem statement

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

A decimal number or an integer.

(Optional) An 'e' or 'E', followed by an integer.

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

(Optional) A sign character (either '+' or '-').

One of the following formats: One or more digits, followed by a dot '.'.

One or more digits, followed by a dot '.', followed by one or more digits.

A dot '.', followed by one or more digits.

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

(Optional) A sign character (either '+' or '-').

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.

Problem statement taken from: https://leetcode.com/problems/valid-number

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

Explanation

In these kinds of problems, we should first check the invalid cases. We return false the moment we discover any invalid case. We must iterate over the string and run a few checks based on the current character. While iterating, we should keep track of whether the signs (+ or -), the exponent e or decimal . has appeared before or not.

We need to ensure below cases are handled in our code:

  1. The characters in the string belong to the set {+, -, ., e, [0-9]}.
  2. No . comes after e or E.
  3. A dot . should be followed by a digit.
  4. The character e should be followed either by +, -, or a digit [0-9].
  5. Any other non-numeric character appearing.
  6. Reaching the end of S without an active number.
  7. No more than one exponent character e or E or one sign or decimal in the string.

Let's check the algorithm.

Algorithm

- set number = false
      exponent = false
      sign = false
      decimal = false

- loop for character in s
  // check if the current char is a number, then set the number flag to true
  - if c >= '0' && c <= '9'
    - number = true

  // if char is an exponent, then verify
  // appeared twice or before any number
  // return false
  // else set exponent to true and all other variables to false
  - else if c == 'e' || c == 'E'
    - if exponent || !number
      - return false
    - else
      - exponent = true, sign = false, number = false, decimal = false
    - if end

  // if char is a sign
  // return false if sign appeared before
  // return false if it appeared after any number
  // return false if it appeared after a decimal .
  // else
  // set sign to true
  - else if c == '+' || c == '-'
    - if sign || number || decimal
      - return false
    - else
      - sign = true
    - if end

  // if char is a decimal
  // return false if decimal appeared before
  // return false if appeared after an exponent
  // else
  // set decimal to true

  // if char is any character apart from number, sign, exponent or decimal
  // return false
  - else
    - return false
- for end

// if a number has not appeared in the string, the number flag will be false
// else it will be true
// We return the number as our answer
- return number

The time complexity of this approach is O(n). The space complexity is O(1).

Let's check our algorithm in C++, Golang, and JavaScript.

C++ solution

class Solution {
public:
    bool isNumber(string s) {
        bool number = false, exponent = false, sign = false, decimal = false;

        for (auto c : s) {
            if (c >= '0' && c <= '9')
                number = true;
            else if (c == 'e' || c == 'E')
                if (exponent || !number)
                    return false;
                else
                    exponent = true, sign = false, number = false, decimal = false;
            else if (c == '+' || c == '-')
                if (sign || number || decimal)
                    return false;
                else
                    sign = true;
            else if (c == '.')
                if (decimal || exponent)
                    return false;
                else
                    decimal = true;
            else
                return false;
        }

        return number;
    }
};

Golang solution

func isNumber(s string) bool {
    number, exponent, sign, decimal := false, false, false, false

    for _, c := range s {
        if c >= '0' && c <= '9' {
            number = true
        } else if c == 'e' || c == 'E' {
            if exponent || !number {
                return false
            } else {
                exponent = true
                sign = false
                number = false
                decimal = false
            }
        } else if c == '+' || c == '-' {
            if sign || number || decimal {
                return false
            } else {
                sign = true
            }
        } else if c == '.' {
            if decimal || exponent {
                return false
            } else {
                decimal = true
            }
        } else {
            return false
        }
    }

    return number
}

JavaScript solution

var isNumber = function(s) {
    let number = false, exponent = false, sign = false, decimal = false;

    for (c of s) {
        if (c >= '0' && c <= '9')
            number = true;
        else if (c == 'e' || c == 'E')
            if (exponent || !number)
                return false;
            else
                exponent = true, sign = false, number = false, decimal = false;
        else if (c == '+' || c == '-')
            if (sign || number || decimal)
                return false;
            else
                sign = true;
        else if (c == '.')
            if (decimal || exponent)
                return false;
            else
                decimal = true;
        else
            return false;
    }

    return number;
};

Dry Run

Let's dry-run our algorithm for a few examples to see how the solution works.

Input: '-90E3'

Step 1: set number = false
            exponent = false
            sign = false
            decimal = false

Step 2: loop for auto c in s
          c = '-'

          if c >= '0' && c <= '9'
            false
          else if c == 'e' || c == 'E'
            false
          else if c == '+' || c == '-'
            true

            if sign || number || decimal
               false || false || false
            else
               sign = true

Step 3: loop for auto c in s
          c = '9'

          if c >= '0' && c <= '9'
            true
            number = true

Step 4: loop for auto c in s
          c = '0'

          if c >= '0' && c <= '9'
            true
            number = true

Step 5: loop for auto c in s
          c = 'E'

          if c >= '0' && c <= '9'
            false
          else if c == 'e' || c == 'E'
            true

            if exponent || !number
               false || !true
               false || false
               false
            else
              exponent = true
              sign = false
              number = false
              decimal = false

Step 6: loop for auto c in s
          c = '3'

          if c >= '0' && c <= '9'
            true
            number = true

Step 7: loop for auto c in s
          String ends

        loop exit

Step 8: return number

We return true.

Input: '99e2.5'

Step 1: set number = false
            exponent = false
            sign = false
            decimal = false

Step 2: loop for auto c in s
          c = '9'

          if c >= '0' && c <= '9'
            true
            number = true

Step 3: loop for auto c in s
          c = '9'

          if c >= '0' && c <= '9'
            true
            number = true

Step 4: loop for auto c in s
          c = 'e'

          if c >= '0' && c <= '9'
            false
          else if c == 'e' || c == 'E'
            true

            if exponent || !number
               false || !true
               false || false
               false
            else
              exponent = true
              sign = false
              number = false
              decimal = false

Step 5: loop for auto c in s
          c = '.'

          if c >= '0' && c <= '9'
            false
          else if c == 'e' || c == 'E'
            false
          else if c == '+' || c == '-'
            false
          else if c == '.'
            true

            if decimal || exponent
               false || true
               true

               return false

The decimal . appeared after the exponent e. We return the answer as false.
Share this post!