Validate if a given string can be interpreted as a decimal number.html
Some examples:"0"
=> true
" 0.1 "
=> true
"abc"
=> false
"1 a"
=> false
"2e10"
=> true
" -90e3 "
=> true
" 1e"
=> false
"e3"
=> false
" 6e-1"
=> true
" 99e2.5 "
=> false
"53.5e93"
=> true
" --6 "
=> false
"-+3"
=> false
"95a54e53"
=> false
java
Note: It is intended for the problem statement to be ambiguous. You should gather all requirements up front before implementing one. However, here is a list of characters that can be in a valid decimal number:git
Of course, the context of these characters also matters in the input.正则表达式
Update (2015-02-10):
The signature of the C++
function had been updated. If you still see your function signature accepts a const char *
argument, please click the reload button to reset your code definition.post
这道验证数字的题比想象中的要复杂的多,有不少状况须要考虑,而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', 还要加上正负号 '+/-", 除了这些字符须要考虑意外,出现了任何其余的字符,能够立刻断定不是数字。下面咱们来一一分析这些出现了也多是数字的特殊字符:ui
1. 空格 ‘ ’: 空格分为两种状况须要考虑,一种是出如今开头和末尾的空格,一种是出如今中间的字符。出如今开头和末尾的空格不影响数字,而一旦中间出现了空格,则立马不是数字。解决方法:预处理时去掉字符的首位空格,中间再检测到空格,则断定不是数字。url
2. 小数点 '.':小数点须要分的状况较多,首先的是小数点只能出现一次,可是小数点能够出如今任何位置,开头(".3"), 中间("1.e2"), 以及结尾("1." ), 并且须要注意的是,小数点不能出如今天然数 'e/E' 以后,如 "1e.1" false, "1e1.1" false。还有,当小数点位于末尾时,前面必须是数字,如 "1." true," -." false。解决方法:开头中间结尾三个位置分开讨论状况。spa
3. 天然数 'e/E':天然数的先后必须有数字,即天然数不能出如今开头和结尾,如 "e" false, ".e1" false, "3.e" false, "3.e1" true。并且小数点只能出如今天然数以前,还有就是天然数前面不能是符号,如 "+e1" false, "1+e" false. 解决方法:开头中间结尾三个位置分开讨论状况。.net
4. 正负号 '+/-",正负号能够再开头出现,能够再天然数e以后出现,但不能是最后一个字符,后面得有数字,如 "+1.e+5" true。解决方法:开头中间结尾三个位置分开讨论状况。
下面咱们开始正式分开头中间结尾三个位置来讨论状况:
1. 在讨论三个位置以前作预处理,去掉字符串首尾的空格,能够采用两个指针分别指向开头和结尾,遇到空格则跳过,分别指向开头结尾非空格的字符。
2. 对首字符处理,首字符只能为数字或者正负号 '+/-",咱们须要定义三个flag在标示咱们是否以前检测到太小数点,天然数和正负号。首字符如为数字或正负号,则标记对应的flag,若不是,直接返回false。
3. 对中间字符的处理,中间字符会出现五种状况,数字,小数点,天然数,正负号和其余字符。
如果数字,标记flag并经过。
如果天然数,则必须是第一次出现天然数,而且前一个字符不能是正负号,并且以前必定要出现过数字,才能标记flag经过。
如果正负号,则以前的字符必须是天然数e,才能标记flag经过。
如果小数点,则必须是第一次出现小数点而且天然数没有出现过,才能标记flag经过。
如果其余,返回false。
4. 对尾字符处理,最后一个字符只能是数字或小数点,其余字符都返回false。
如果数字,返回true。
如果小数点,则必须是第一次出现小数点而且天然数没有出现过,还有前面必须是数字,才能返回true。
解法一:
class Solution { public: bool isNumber(string s) { int len = s.size(); int left = 0, right = len - 1; bool eExisted = false; bool dotExisted = false; bool digitExisited = false; // Delete spaces in the front and end of string while (s[left] == ' ') ++left; while (s[right] == ' ') --right; // If only have one char and not digit, return false if (left >= right && (s[left] < '0' || s[left] > '9')) return false; //Process the first char if (s[left] == '.') dotExisted = true; else if (s[left] >= '0' && s[left] <= '9') digitExisited = true; else if (s[left] != '+' && s[left] != '-') return false; // Process the middle chars for (int i = left + 1; i <= right - 1; ++i) { if (s[i] >= '0' && s[i] <= '9') digitExisited = true; else if (s[i] == 'e' || s[i] == 'E') { // e/E cannot follow +/-, must follow a digit if (!eExisted && s[i - 1] != '+' && s[i - 1] != '-' && digitExisited) eExisted = true; else return false; } else if (s[i] == '+' || s[i] == '-') { // +/- can only follow e/E if (s[i - 1] != 'e' && s[i - 1] != 'E') return false; } else if (s[i] == '.') { // dot can only occur once and cannot occur after e/E if (!dotExisted && !eExisted) dotExisted = true; else return false; } else return false; } // Process the last char, it can only be digit or dot, when is dot, there should be no dot and e/E before and must follow a digit if (s[right] >= '0' && s[right] <= '9') return true; else if (s[right] == '.' && !dotExisted && !eExisted && digitExisited) return true; else return false; } };
上面的写法略为复杂,咱们尝试着来优化一下,根据上面的分析,全部的字符能够分为六大类,空格,符号,数字,小数点,天然底数和其余字符,咱们须要五个标志变量,num, dot, exp, sign分别表示数字,小数点,天然底数和符号是否出现,numAfterE表示天然底数后面是否有数字,那么咱们分别来看各类状况:
- 空格: 咱们须要排除的状况是,当前位置是空格然后面一位不为空格,可是以前有数字,小数点,天然底数或者符号出现时返回false。
- 符号:符号前面若是有字符的话必须是空格或者是天然底数,标记sign为true。
- 数字:标记num和numAfterE为true。
- 小数点:若是以前出现太小数点或者天然底数,返回false,不然标记dot为true。
- 天然底数:若是以前出现过天然底数或者以前从未出现过数字,返回false,不然标记exp为true,numAfterE为false。
- 其余字符:返回false。
最后返回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] != ' ') 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') { 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,天理难容呀~
相似题目:
参考资料:
https://leetcode.com/problems/valid-number/
https://discuss.leetcode.com/topic/9490/clear-java-solution-with-ifs