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"
.
A valid number is defined using one of the following definitions:
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:
'.'
. 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.
## Valid Number
This problem asks us to determine whether a given string represents a valid number, considering various formats such as integers, decimals, and exponents. We need to account for optional signs, digits, dots, and exponent notations ('e' or 'E').
### Brute Force Solution
A brute-force approach would involve manually checking all possible combinations of characters and their positions according to the rules. This can be done using a series of if-else statements or regular expressions. However, this is not efficient and prone to errors due to the complexity of the rules.
```python
def isNumber_bruteforce(s: str) -> bool:
try:
float(s)
# Additional checks to rule out cases like 'inf' and 'nan'
if s.lower() == 'inf' or s.lower() == '-inf' or s.lower() == 'nan':
return False
return True
except ValueError:
return False
A more robust and elegant solution involves using a state machine to parse the input string. We can define different states representing different parts of a valid number (e.g., integer part, decimal part, exponent part) and transitions between these states based on the input characters.
def isNumber(s: str) -> bool:
s = s.strip() # Remove leading/trailing whitespace
n = len(s)
state = 0
# 0: initial, 1: digit (before dot), 2: dot, 3: digit (after dot),
# 4: e, 5: sign after e, 6: digit after e, 7: trailing spaces
states = [
{" ": 0, "s": 1, "d": 1, ".": 2},
{"d": 1, ".": 2, "e": 4, " ": 7},
{"d": 3, "e": 4, " ": 7},
{"d": 3, "e": 4, " ": 7},
{"s": 5, "d": 6},
{"d": 6},
{"d": 6, " ": 7},
{" ": 7}
]
def to_state_key(char):
if char.isdigit():
return "d"
elif char in ["+", "-"]:
return "s"
else:
return char
for char in s:
key = to_state_key(char)
if key in states[state]:
state = states[state][key]
else:
return False
return state in [1, 3, 6, 7]
The time complexity of the state machine solution is O(n), where n is the length of the input string. This is because we iterate through the string once, and the state transitions take constant time.
The space complexity is O(1), as we use a fixed number of states and variables regardless of the input string length.
False
due to the s.strip()
and subsequent checks.s.strip()
method removes leading and trailing whitespace, ensuring correct parsing.False
.