剑指 Offer 20. 表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、“5e2”、"-123"、“3.1416”、"-1E-16"、“0123"都表示数值,但"12e”、“1a3.14”、“1.2.3”、"±5"及"12e+5.4"都不是。
思路
注意隐藏规则:
- 字符串首尾会出现空格
- 小数点左右两侧至少有一侧为有整数
其实就是状态的定义以及状态转移的考虑,注意把所有状态都考虑进去就可以了。
状态:
- 起始空格
- 符号位
- 整数部分
- 左侧有整数小数点
- 左侧没整数小数点
- 小数部分
- 字符e
- 字符e的符号位
- 指数部分
- 末尾
字符类型:
- 数字
- 小数点
- 空格
- 符号e
- 正负号
结束时只能为状态3、4、6、9、10,否则返回false。
代码
class Solution {
public:
enum State {
STATE_INITIAL,
STATE_SIGN,
STATE_INTEGER,
STATE_POINT,
STATE_POINT_WITHOUT_INT,
STATE_FRACTION,
STATE_EXP,
STATE_EXP_SIGN,
STATE_EXP_INTEGER,
STATE_END,
};
enum CharType {
CHAR_NUMBER,
CHAR_POINT,
CHAR_SPACE,
CHAR_EXP,
CHAR_SIGN,
CHAR_ILLEGAL,
};
CharType toCharType(const char& c) {
if(c >= '0' && c <= '9') {
return CHAR_NUMBER;
}
else if(c == '.') {
return CHAR_POINT;
}
else if(c == ' ') {
return CHAR_SPACE;
}
else if(c == '+' || c == '-') {
return CHAR_SIGN;
}
else if(c == 'e' || c == 'E') {
return CHAR_EXP;
}
else {
return CHAR_ILLEGAL;
}
}
bool isNumber(string s) {
unordered_map<State, unordered_map<CharType, State>> transfer {
{
STATE_INITIAL, {
{CHAR_NUMBER, STATE_INTEGER},
{CHAR_SPACE, STATE_INITIAL},
{CHAR_POINT, STATE_POINT_WITHOUT_INT},
{CHAR_SIGN, STATE_SIGN},
}
}, {
STATE_SIGN, {
{CHAR_NUMBER, STATE_INTEGER},
{CHAR_POINT, STATE_POINT_WITHOUT_INT},
}
}, {
STATE_INTEGER, {
{CHAR_NUMBER, STATE_INTEGER},
{CHAR_POINT, STATE_POINT},
{CHAR_EXP, STATE_EXP},
{CHAR_SPACE, STATE_END},
}
}, {
STATE_POINT, {
{CHAR_NUMBER, STATE_FRACTION},
{CHAR_SPACE, STATE_END},
{CHAR_EXP, STATE_EXP},
}
}, {
STATE_POINT_WITHOUT_INT, {
{CHAR_NUMBER, STATE_FRACTION},
}
}, {
STATE_FRACTION, {
{CHAR_NUMBER, STATE_FRACTION},
{CHAR_SPACE, STATE_END},
{CHAR_EXP, STATE_EXP},
}
}, {
STATE_EXP, {
{CHAR_NUMBER, STATE_EXP_INTEGER},
{CHAR_SIGN, STATE_EXP_SIGN},
}
}, {
STATE_EXP_SIGN, {
{CHAR_NUMBER, STATE_EXP_INTEGER},
}
}, {
STATE_EXP_INTEGER, {
{CHAR_NUMBER, STATE_EXP_INTEGER},
{CHAR_SPACE, STATE_END},
}
}, {
STATE_END, {
{CHAR_SPACE, STATE_END},
}
},
};
int n = s.size();
State st = STATE_INITIAL;
for(int i = 0; i < n; i++) {
CharType tmp = toCharType(s[i]);
if(transfer[st].find(tmp) == transfer[st].end()) {
return false;
}
else {
st = transfer[st][tmp];
}
}
return st == STATE_INTEGER || st == STATE_POINT || st == STATE_FRACTION || st == STATE_EXP_INTEGER || st == STATE_END;
}
};