题目
Validate if a given string is numeric.
Some examples:
“0” => true
” 0.1 ” => true
“abc” => false
“1 a” => false
“2e10” => true
Note: It is intended for the problem statement to be ambiguous. You should gather all requirements up front before implementing one.
解题思路
解决这类问题,我们可以画出一个识别数字的DFA,通过从前向后扫描字符串中的每一个字符来进行状态的迁移,当扫描到字符串的尾部时,看当前状态时否为DFA的终态,若是则说明该字符串为有效数字,否则为无效数字。我画的DFA如下:(不唯一,仅供参考)
在上述DFA中,始态为q0;终态为:q2,q3,q4,q7,q10。
比如要识别的字符串为“-12.34e10”,则识别过程为:q0→q1→q2→q2→q3→q4→q4→q5→q10→q10。可见最后状态落在了q10(终态),说明该字符串是一个有效数字。
在这里还需要注意的是字符串中的空格问题:
- “ 123”有效
- “123 ”有效
- “ 123 ”有效
- “1 23”无效
即字符串的首部和尾部连续空格可以跳过,只需要识别中间部分的字符即可。
AC代码
class Solution {
public:
bool isNumber(string s) {
int begin = s.find_first_not_of(' '), end = s.find_last_not_of(' ');//跳过首部和尾部的连续空格
int state = 0;
for(int i = begin; i <= end; ++i)
{
if((s[i] == '+' || s[i] == '-') && state == 0)
{
state = 1;
continue;
}
if(s[i] == '.' && state == 0)
{
state = 8;
continue;
}
if(isdigit(s[i]) && (state == 0 || state == 1 || state == 2))
{
state = 2;
continue;
}
if(s[i] == '.' && state == 2)
{
state = 3;
continue;
}
if(isdigit(s[i]) && (state == 3 || state == 4))
{
state = 4;
continue;
}
if(s[i] == 'e' && (state == 2 || state == 3 || state == 4 || state == 7))
{
state = 5;
continue;
}
if(s[i] == '.' && state == 1)
{
state = 6;
continue;
}
if(isdigit(s[i]) && (state == 6 || state == 7 || state == 8))
{
state = 7;
continue;
}
if((s[i] == '+' || s[i] == '-') && state == 5)
{
state = 9;
continue;
}
if(isdigit(s[i]) && (state == 5 || state == 9 || state == 10))
{
state = 10;
continue;
}
return false;//遇到非法字符,直接返回false
}
return state == 2 || state == 3 || state == 4 || state == 7 || state == 10;
}
};
在上面的DFA中,可能你纳闷q3为什么也是终态,难道“123.”也是有效数字?是的,按常理来看“123.”不应该为有效的数字,但是在本题中判定机制把这类字符串也认定为有效数字,类似的还有“.123”,“123.e10”。所以存在q3遇到‘e’迁移到q5 , q0遇到‘.’迁移到q8这类情况。