题目链接:
https://leetcode-cn.com/problems/biao-shi-shu-zhi-de-zi-fu-chuan-lcof/
难度:中等
剑指 Offer 20. 表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
例如,字符串"+100"、"5e2"、"-123"、"3.1416"、"-1E-16"、"0123"都表示数值,
但"12e"、"1a3.14"、"1.2.3"、"+-5"及"12e+5.4"都不是。
这个题 很迷 搞得我很迷。。。。
不过 确实是不会做 看完题目后 感觉有点熟悉 编译原理???然后题解 卧槽 真是! 有限状态自动机 嗯 我知道 也只是知道 之前学的全忘了。。。
具体描述 ->题解
class Solution {
public:
// 十种状态
enum State {
// 初始状态
STATE_INITIAL,
// 符号位
STATE_INT_SIGN,
// 整数
STATE_INTEGER,
// 小数点(左侧有整数))
STATE_POINT,
// 小数点(左侧无整数))
STATE_POINT_WITHOUT_INT,
// 小数部分
STATE_FRACTION,
// 指数字符 e
STATE_EXP,
// 指数符号
STATE_EXP_SIGN,
// 指数数字
STATE_EXP_NUMBER,
// 结束状态
STATE_END,
};
// 改变状态的类型
enum CharType {
// 数字
CHAR_NUMBER,
// 指数e
CHAR_EXP,
// 小数点
CHAR_POINT,
// 符号(+ -)
CHAR_SIGN,
// 空格
CHAR_SPACE,
// 非法
CHAR_ILLEGAL,
};
// 返回字符类型 CharType
CharType getCharType(char s) {
if (s >= '0' && s<= '9') {
return CHAR_NUMBER;
} else if (s == 'e' || s == 'E') {
return CHAR_EXP;
} else if (s == '.') {
return CHAR_POINT;
} else if (s == '+' || s == '-') {
return CHAR_SIGN;
} else if (s == ' ') {
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 n=s.size();
State state = STATE_INITIAL;
for(int i=0;i<n;++i){
CharType chartype=getCharType(s[i]);
if(transfer[state].find(chartype)==transfer[state].end()){
return false;
}else{
state=transfer[state][chartype];
}
}
return state == STATE_INTEGER || state == STATE_POINT || state == STATE_FRACTION || state == STATE_EXP_NUMBER || state == STATE_END;
}
};
还有种思路 只要你清楚所有数的规则就可以了 直接进行判断 只不过有点繁琐 (看的别人的思路。。。) 我是不太熟悉的
class Solution {
public:
bool judgeLeft(string s){
if(s.empty()){
return false;
}
// 去除正负号
if(s[0]=='+'||s[0]=='-'){
s.erase(0, 1);
}
// flag记录是否有一个小数点
bool flag = false;
for(int i = 0; i < s.size(); ++i){
if(isdigit(s[i])){
continue;
}
if(s[i]=='.'){
if(flag){
//有多个小数点,返回false
return false;
}
flag=true;
}else{
return false;
}
}
return !s.empty()&&s!= ".";
}
bool judgeRight(string s){
if(s.empty()){
return false;
}
if(s[0]=='+'||s[0]=='-'){
s.erase(0, 1);
}
//右边不能出现小数点
for(int i=0;i<s.size();++i){
if(!isdigit(s[i])){
return false;
}
}
return !s.empty();
}
bool isNumber(string s) {
// 去除首位空格 start
//第一个不是空格的位置
auto i=s.find_first_not_of(' ');
if(i==string::npos){
return false;
}
//最后一个不是空格的位置
auto j=s.find_last_not_of(' ');
//去除首尾空格
s=s.substr(i,j-i+1);
// 去除首位空格 end
// 去除空格后s为空 false
if(s.empty()){
return false;
}
// 找到指数e
auto k=s.find_first_of('E');
if(k!=string::npos){
s[k] = 'e';
}
auto pos=s.find('e');
//
if(pos==string::npos){
return judgeLeft(s);
}
return judgeLeft(s.substr(0,pos))&&judgeRight(s.substr(pos+1));
}
};