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:
1. One or more digits, followed by a dot'.'
.
2. One or more digits, followed by a dot'.'
, followed by one or more digits.
3. 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
ifs
is a 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'.'
.
这道验证数字的题比想象中的要复杂的多,有很多情况需要考虑,而OJ上给这道题的分类居然是Easy,Why? 而10.9% 的全场最低的Accept Rate正说明这道题的难度,网上有很多解法,有利用有限自动机Finite Automata Machine的程序写的简洁优雅 (http://blog.csdn.net/kenden23/article/details/18696083), 还有利用正则表达式,更是写的丧心病狂的简洁 (http://blog.csdn.net/fightforyourdream/article/details/12900751)。而我主要还是用最一般的写法,参考了网上另一篇博文 (http://yucoding.blogspot.com/2013/05/leetcode-question-118-valid-number.html),处理各种情况。
首先,从题目中给的一些例子可以分析出来,我们所需要关注的除了数字以外的特殊字符有空格 ‘ ’, 小数点 ‘.’, 自然数 ‘e/E’, 还要加上正负号 ‘+/-“, 除了这些字符需要考虑意外,出现了任何其他的字符,可以马上判定不是数字。下面我们来一一分析这些出现了也可能是数字的特殊字符:
- 空格 ‘ ’: 空格分为两种情况需要考虑,一种是出现在开头和末尾的空格,一种是出现在中间的字符。出现在开头和末尾的空格不影响数字,而一旦中间出现了空格,则立马不是数字。解决方法:若发现空格后面一位不为空格,但是之前有数字,小数点,自然底数或者符号出现时,则判定不是数字。
- 小数点 ‘.’:小数点需要分的情况较多,首先的是小数点只能出现一次,但是小数点可以出现在任何位置,开头(“.3”), 中间(“1.e2”), 以及结尾(“1.” ), 而且需要注意的是,小数点不能出现在自然数 ‘e/E’ 之后,如 “1e.1” false, “1e1.1” false。还有,当小数点位于末尾时,前面必须是数字,如 “1.” true,” -.” false。解决方法:如果之前出现过小数点或者自然底数,则判定不是数字。
- 自然数 ‘e/E’:自然数的前后必须有数字,即自然数不能出现在开头和结尾,如 “e” false, “.e1” false, “3.e” false, “3.e1” true。而且小数点只能出现在自然数之前,还有就是自然数前面不能是符号,如 “+e1” false, “1+e” false. 解决方法:如果之前出现过自然底数或者之前从未出现过数字,则判定不是数字。
- 正负号 ‘+/-“,正负号可以在开头出现,可以在自然数e之后出现,但不能是最后一个字符,后面得有数字,如 “+1.e+5” true。解决方法:若之前不是空格或者自然底数,则判定不是数字。
根据上面的分析,所有的字符可以分为六大类,空格,符号,数字,小数点,自然底数和其他字符,我们需要五个标志变量,num, dot, exp, sign 分别表示数字,小数点,自然底数和符号是否出现,numAfterE 表示自然底数后面是否有数字,那么分别来看各种情况:
1. 空格: 需要排除的情况是,当前位置是空格而后面一位不为空格,但是之前有数字,小数点,自然底数或者符号出现时返回 false,例如 “1 3”, “. -“, “e .”, “+ e”。
2. 符号:符号前面如果有字符的话必须是空格或者是自然底数,标记 sign 为 true,例如 “1+”, “.+”, “++”。
3. 数字:标记 num 和 numAfterE 为 true。
4. 小数点:如果之前出现过小数点或者自然底数,返回 false,否则标记 dot 为 true,例如 “.1.”, “e1.”。
5. 自然底数:如果之前出现过自然底数或者之前从未出现过数字,返回 false,否则标记 exp 为 true,numAfterE 为 false(注意自然底数后面必须要有数字,这个可以留到最后判断),例如 “-e5”, “e3e”, “4e+”, “.e1”, “3.e”。
6. 其他字符:返回 false,例如 “abc”。
最后返回 num && numAfterE 即可。
class Solution {
public:
bool isNumber(string s) {
bool num = false, numAfterE = true, dot = false, exp = false, sign = false;
int n = s.size();
for (int i = 0; i < n; ++i) {
if (s[i] == ' ') {
if (i < n - 1 && s[i + 1] != ' ' && (num || dot || exp || sign)) return false;
} else if (s[i] == '+' || s[i] == '-') {
if (i > 0 && s[i - 1] != 'e' && s[i - 1] != 'E' && s[i - 1] != ' ') return false;
sign = true;
} else if (s[i] >= '0' && s[i] <= '9') {
num = true;
numAfterE = true;
} else if (s[i] == '.') {
if (dot || exp) return false;
dot = true;
} else if (s[i] == 'e' || s[i] == 'E') {
if (exp || !num) return false;
exp = true;
numAfterE = false;
} else return false;
}
return num && numAfterE;
}
};
这道题给了例子不够用,下面这些例子都是我在调试的过程中出现过的例子,用来参考:
string s1 = "0"; // True
string s2 = " 0.1 "; // True
string s3 = "abc"; // False
string s4 = "1 a"; // False
string s5 = "2e10"; // True
string s6 = "-e10"; // False
string s7 = " 2e-9 "; // True
string s8 = "+e1"; // False
string s9 = "1+e"; // False
string s10 = " "; // False
string s11 = "e9"; // False
string s12 = "4e+"; // False
string s13 = " -."; // False
string s14 = "+.8"; // True
string s15 = " 005047e+6"; // True
string s16 = ".e1"; // False
string s17 = "3.e"; // False
string s18 = "3.e1"; // True
string s19 = "+1.e+5"; // True
string s20 = " -54.53061"; // True
string s21 = ". 1"; // False
感想:这道题实在是太烦了,情况太多了,这再不是Hard,天理难容呀~
Github 同步地址:
https://github.com/grandyang/leetcode/issues/65
类似题目:
参考资料:
https://leetcode.com/problems/valid-number/
https://discuss.leetcode.com/topic/9490/clear-java-solution-with-ifs
LeetCode All in One 题目讲解汇总(持续更新中…)
(欢迎加入博主的知识星球,博主将及时答疑解惑,并分享刷题经验与总结,快快加入吧~)
微信打赏
|
Venmo 打赏
—|—
转载请注明来源于 Grandyang 的博客 (grandyang.com),欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 grandyang@qq.com