请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
数值(按顺序)可以分成以下几个部分:
- 若干空格
- 一个 小数 或者 整数
- (可选)一个
'e'
或'E'
,后面跟着一个 整数 - 若干空格
小数(按顺序)可以分成以下几个部分:
- (可选)一个符号字符(
'+'
或'-'
) 下述格式之一:
- 至少一位数字,后面跟着一个点
'.'
- 至少一位数字,后面跟着一个点
'.'
,后面再跟着至少一位数字 - 一个点
'.'
,后面跟着至少一位数字
- 至少一位数字,后面跟着一个点
整数(按顺序)可以分成以下几个部分:
- (可选)一个符号字符(
'+'
或'-'
) - 至少一位数字
部分数值列举如下:
["+100", "5e2", "-123", "3.1416", "-1E-16", "0123"]
部分非数值列举如下:
["12e", "1a3.14", "1.2.3", "+-5", "12e+5.4"]
示例 1:
输入:s = "0"
输出:true
示例 2:
输入:s = "e"
输出:false
示例 3:
输入:s = "."
输出:false
示例 4:
输入:s = " .1 "
输出:true
提示:
1 <= s.length <= 20
s
仅含英文字母(大写和小写),数字(0-9
),加号'+'
,减号'-'
,空格' '
或者点'.'
。
思路:
有限状态机,枚举状态,及状态遇到字符,转换为其他状态。从左到右枚举字符串,当前字符所代表的含义就是一个状态,空格就用初始状态表示,+、-号是一个状态,字符0~9是一个状态,小数点是一个状态,小数点前后有空格的也是一个状态,小数部分是一个状态,e或者E是一个状态,指数部分是一个状态,不同的状态下遇到适合的字符,转换为下一个状态,比如初始状态遇到空格还是初始状态,初始状态遇到+、-号转换为符号状态
然后定义字符类别:加减符号、数字符号、小数点、指数符号等等。
代码:
class Solution {
public:
enum State {
STATE_INITIAL,//初始状态
STATE_INT_SIGN,//整数部分的加减号
STATE_INTEGER,//整数
STATE_POINT,//小数点
STATE_POINT_WITHOUT_INT,//小数点前有空格或啥没有
STATE_FRACTION,//小数部分
STATE_EXP,//指数符号e或者E
STATE_EXP_SIGN,//指数部分的加减号
STATE_EXP_NUMBER,//指数部分数字
STATE_END//结束状态
};
enum CharType {
CHAR_SPACE,//空格
CHAR_SIGN,//加减号
CHAR_NUMBER,//数字
CHAR_POINT,//小数点
CHAR_EXP,//指数符号e或者E
CHAR_ILLEGAL//非法符号
};
CharType toCharType(char ch) {
if(ch >= '0' && ch <= '9') {
return CHAR_NUMBER;
}
else if(ch == 'e' || ch == 'E') {
return CHAR_EXP;
}
else if(ch == '.') {
return CHAR_POINT;
}
else if(ch == '+' || ch == '-') {
return CHAR_SIGN;
}
else if(ch == ' ') {
return CHAR_SPACE;
}
else {
return CHAR_ILLEGAL;
}
}
bool isNumber(string s) {
unordered_map<State, unordered_map<CharType, State>> transfer{
{
STATE_INITIAL, {//初始状态只能接受空格、数字、小数点、加减号
{CHAR_SPACE, STATE_INITIAL},
{CHAR_NUMBER, STATE_INTEGER},
{CHAR_POINT, STATE_POINT_WITHOUT_INT},
{CHAR_SIGN, STATE_INT_SIGN}
}
},{
STATE_INT_SIGN, {//整数加减符号只能接受数字、小数点
{CHAR_NUMBER, STATE_INTEGER},
{CHAR_POINT, STATE_POINT_WITHOUT_INT}
}
},{
STATE_INTEGER, {//整数部分只能接受数字、指数符号、小数点、和空格
{CHAR_NUMBER, STATE_INTEGER},
{CHAR_EXP, STATE_EXP},
{CHAR_POINT, STATE_POINT},
{CHAR_SPACE, STATE_END}
}
},{
STATE_POINT, {//小数点只能接受数字、指数符号、空格
{CHAR_NUMBER, STATE_FRACTION},
{CHAR_EXP, STATE_EXP},
{CHAR_SPACE, STATE_END}
}
},{
STATE_POINT_WITHOUT_INT, {//不带整数的小数点只能接受数字
{CHAR_NUMBER, STATE_FRACTION}
}
},{
STATE_FRACTION, {//小数部分只能接受数字、指数符号、空格
{CHAR_NUMBER, STATE_FRACTION},
{CHAR_EXP, STATE_EXP},
{CHAR_SPACE, STATE_END}
}
},{
STATE_EXP, {//指数符号只能接受数字和加减号
{CHAR_NUMBER, STATE_EXP_NUMBER},
{CHAR_SIGN, STATE_EXP_SIGN}
}
},
{
STATE_EXP_SIGN, {//指数部分的加减号只能接受数字
{CHAR_NUMBER, STATE_EXP_NUMBER}
}
},{
STATE_EXP_NUMBER,{//指数部分的数字只能接受数字和空格
{CHAR_NUMBER, STATE_EXP_NUMBER},
{CHAR_SPACE, STATE_END}
}
},{
STATE_END, {//结束状态只能接受空格
{CHAR_SPACE, STATE_END}
}
}
};
int len = s.length();
State state = STATE_INITIAL;
for(int i = 0;i < len;i++) {
CharType type = toCharType(s[i]);
if(transfer[state].find(type) == transfer[state].end()) {
//如果找不到当前状态对应的合法字符类别,则说明不是数字
return false;
}
else {
state = transfer[state][type];
}
}
return state == STATE_INTEGER || state == STATE_POINT || state == STATE_FRACTION || state == STATE_EXP_NUMBER || state == STATE_END;
}
};