Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LeetCode] 65. Valid Number #65

Open
grandyang opened this issue May 30, 2019 · 2 comments
Open

[LeetCode] 65. Valid Number #65

grandyang opened this issue May 30, 2019 · 2 comments

Comments

@grandyang
Copy link
Owner

grandyang commented May 30, 2019


请点击下方图片观看讲解视频
Click below image to watch YouTube Video
Video

A valid number can be split up into these components (in order):

  1. A decimal number or an integer.
  2. (Optional) An 'e' or 'E', followed by an integer.

A decimal number can be split up into these components (in order):

  1. (Optional) A sign character (either '+' or '-').
  2. 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):

  1. (Optional) A sign character (either '+' or '-').
  2. 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 同步地址:

#65

类似题目:

String to Integer (atoi)

参考资料:

https://leetcode.com/problems/valid-number/

https://discuss.leetcode.com/topic/9490/clear-java-solution-with-ifs

LeetCode All in One 题目讲解汇总(持续更新中...)

(欢迎加入博主的知识星球,博主将及时答疑解惑,并分享刷题经验与总结,快快加入吧~)

知识星球 喜欢请点赞,疼爱请打赏❤️~.~

微信打赏

|

Venmo 打赏


---|---

@jimbinc
Copy link

jimbinc commented May 23, 2020

隐隐感觉,
easy是能用自带函数和暴力破解的
medium是需要算法的
hard是需要改装算法的

@grandyang
Copy link
Owner Author

隐隐感觉,
easy是能用自带函数和暴力破解的
medium是需要算法的
hard是需要改装算法的

神总结~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants