65. 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:
- An integer number followed by an optional exponent.
- 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:
- Digits followed by a dot ‘.’.
- Digits followed by a dot ‘.’ followed by digits.
- 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 ‘.’.
From: LeetCode
Link: 65. Valid Number
Solution:
Ideas:
1. Flag Variables:
- numSeen: This flag indicates whether at least one digit has been encountered in the string. It helps ensure there’s a valid numeric component in the string.
- dotSeen: Tracks if a decimal point has been seen. This prevents multiple decimals which would invalidate the format.
- eSeen: Indicates if an exponent character (e or E) has appeared, ensuring no repeated exponents and that the exponent is properly formatted.
- numberAfterE: After an exponent is seen, this flag checks if a valid number follows. The presence of a number after the exponent is crucial for a valid scientific notation.
2. Initial Whitespace Handling:
- The loop while (*s == ’ ') { s++; } moves the pointer s past any leading white spaces. Although the problem constraints do not mention spaces, handling them might make the function more generally applicable.
3. Character-by-Character Validation:
- The for loop iterates through each character of the string:
Digits: On encountering a digit, it sets numSeen to true and numberAfterE to true, indicating that there’s a valid number component.- Decimal Point (‘.’): Valid only if no previous decimal point or exponent has been seen (dotSeen or eSeen are false).
- Exponent (‘e’ or ‘E’): Valid only if no previous exponent has been seen and there has been at least one digit before it. It sets eSeen to true and expects digits to follow (numberAfterE to false).
- Signs (‘+’ or ‘-’): Signs are valid only at the beginning of the string or immediately following an exponent.
Invalid Characters: Any character that is not a digit, a sign, a decimal point, or an exponent character leads to an immediate return of false.
4. Final Validity Check:
- After exiting the loop, the function checks if at least one number has been seen (numSeen) and if a valid number follows any e or E (numberAfterE). This final validation ensures the overall string represents a valid number format.
5. Edge Case and Error Handling:
- The function is designed to immediately reject strings upon encountering invalid scenarios, making it efficient in terms of runtime, especially for strings that fail early in the validation process.
Code:
bool isNumber(char* s) {// State flagsbool numSeen = false;bool dotSeen = false;bool eSeen = false;bool numberAfterE = true;// Trim leading whitespacewhile (*s == ' ') {s++;}// Process each characterfor (int i = 0; s[i] != '\0'; i++) {if (isdigit(s[i])) {numSeen = true;numberAfterE = true;} else if (s[i] == '.') {// There must not be a dot or 'e'/'E' already seenif (dotSeen || eSeen) {return false;}dotSeen = true;} else if (s[i] == 'e' || s[i] == 'E') {// There must not be an 'e'/'E' already seen and there must be a number before itif (eSeen || !numSeen) {return false;}eSeen = true;numberAfterE = false;} else if (s[i] == '+' || s[i] == '-') {// Sign must come after 'e' or 'E', or be at the startif (i > 0 && (s[i-1] != 'e' && s[i-1] != 'E')) {return false;}} else {// Invalid characterreturn false;}}// Trim trailing whitespacewhile (*s == ' ') {s++;}// Valid number if we've seen a number and if after 'e'/'E' there is also a numberreturn numSeen && numberAfterE;
}