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