【LeetCode】65.Valid Number【有限状态机&正则表达式】

任务只有一句话判断输入的数字是否合法。说真的,看了给的十几个例子我又百度了一下才最终弄清规则。特别需要注意的是诸如+.5和90.这样的数一开始以为不合法,提交错误后才知道是可以的,小数点前或者后可以没有数字。首先只想到了各种ifelse无限嵌套,顿时索然无味一点都不想写,所以以下是百度看到思想后再写的。(以我的代码风格肯定也不会用enum,直接012345就完事了)

Validate if a given string can be interpreted as a decimal number.

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


一、有限状态机 

还记得初学有限状态机好长时间都一知半解,最后终于恍然大悟,是个挺神奇的东西,于是后来考完试就没用过了,没成想在这里又遇上了。通过分析可以知道有6种可能的字符:非法输入(就是后五种之外的字符)、空格、正负号、小数点、数字、e/E。9种正确或者暂时不能判断是否正确的状态:(其中1478合法,其他暂时不能判断)


0、空格(只有空格,以下八种前面可以有任意数量空格)

1、数(不含小数点的数,可以含正负号)

2、点(可以含正负号)

3、正/负号(只有正负号)

4、点+数(在1基础上含小数点的数)

5、...+e/E(前面合法+e/E)

6、...+e/E+正/负号(前面合法+e/E+正负号)

7、...+e/E+数(此处的数同1,不能有小数点)

8、合法+空格(末尾可以有任意数量空格)


这9种情况似乎很复杂其实拿笔几分钟就推出来了,之间的转换关系,如果画图可能就是一张蜘蛛网,建议直接填二维数组,填完再对照以下代码:

class Solution {
public:
    bool isNumber(string s) {
        enum InputType {INVALID,SPACE,SIGN,DIGIT,DOT,EXPONENT};
        int transTable[9][6] = {
            {-1,0,3,1,2,-1},
            {-1,8,-1,1,4,5},
            {-1,-1,-1,4,-1,-1},
            {-1,-1,-1,1,2,-1},
            {-1,8,-1,4,-1,5},
            {-1,-1,6,7,-1,-1},
            {-1,-1,-1,7,-1,-1},
            {-1,8,-1,7,-1,-1},
            {-1,8,-1,-1,-1,-1}
        };
        int state = 0;
        for (int i = 0;i < s.size();i++){
            InputType input = INVALID;
            if (s[i] == ' ')    input = SPACE;
            else if(s[i]=='+' || s[i]=='-')   input = SIGN;
            else if(isdigit(s[i]))  input = DIGIT;
            else if(s[i] == '.')    input = DOT;
            else if(s[i]=='e' || s[i]=='E') input = EXPONENT;
            if ((state = transTable[state][input]) == -1)
                return false;
        }
        return (state==1 || state==4 || state==7 || state==8);
    }
};

二、正则表达式 

此题也可以用正则表达式做,先去掉首尾空格然后去和正则表达式匹配,我就不具体解释了免得越说越乱,正则表达式的规则参考https://www.cnblogs.com/guozht/p/7610877.html。我补充一点,在C++中\d要写成双斜杠的\\d。代码超级简短,但是没有有限状态机舒服。

class Solution {
public:
    bool isNumber(string s) {
        s.erase(0,s.find_first_not_of(" "));
        s.erase(s.find_last_not_of(" ") + 1);
        if (s.empty())  return false;
        string p = "[+-]?(\\d+\\.?|\\.\\d+)\\d*(e[+-]?\\d+)?";
        return regex_match(s, regex(p));
    }
};

最后有一点奇怪的是,正则表达式在LeetCode上耗时1504ms,几乎就要超时了,相比之下同样的方法java只用了38ms,不知是何缘故。 

 

你可能感兴趣的:(LeetCode)