题目大意:给你一个字符串,问他是否是合法字符
题目思路:最开始以为是个大模拟,写了半天,各种特判才放过去,评论区有很多更好的分类方法,比如分为A.BeC这种情况,然后分为有符号数和无符号数的情况特判,这种特判是我见过的最好的做法了,秒杀自动机的做法。
不过标程还是采用了有限自动机的做法,所以还是把重点放在有限自动机上,最根本的状态就在下面这张图上,具体的分析可以见官方题解,有了转移状态,就可以很好的写出代码了。
时间复杂度&&空间复杂度:O(n)&O(1)
非有限自动机做法:
class Solution {
private int index = 0;//全局索引
private boolean scanUnsignedInteger(String str) {
//是否包含无符号数
int before = index;
while(str.charAt(index) >= '0' && str.charAt(index) <= '9')
index++;
return index > before;
}
private boolean scanInteger(String str) {
//是否包含有符号数
if(str.charAt(index) == '+' || str.charAt(index) == '-')
index++;
return scanUnsignedInteger(str);
}
public boolean isNumber(String s) {
//空字符串
if(s == null || s.length() == 0)
return false;
//添加结束标志
s = s + '|';
//跳过首部的空格
while(s.charAt(index) == ' ')
index++;
boolean numeric = scanInteger(s); //是否包含整数部分
if(s.charAt(index) == '.') {
index++;
//有小数点,处理小数部分
//小数点两边只要有一边有数字就可以,所以用||,
//注意scanUnsignedInteger要在前面,否则不会进
numeric = scanUnsignedInteger(s) || numeric;
}
if((s.charAt(index) == 'E' || s.charAt(index) == 'e')) {
index++;
//指数部分
//e或E的两边都要有数字,所以用&&
numeric = numeric && scanInteger(s);
}
//跳过尾部空格
while(s.charAt(index) == ' ')
index++;
return numeric && s.charAt(index) == '|' ;
}
}
有限自动机做法:
class Solution {
public:
enum State{
STATE_INITIAL,
STATE_INT_SIGN,
STATE_INTEGER,
STATE_POINT,
STATE_POINT_WITHOUT_INT,
STATE_FRACTION,
STATE_EXP,
STATE_EXP_SIGN,
STATE_EXP_NUMBER,
STATE_END,
};
enum CharType{
CHAR_NUMBER,
CHAR_EXP,
CHAR_POINT,
CHAR_SIGN,
CHAR_SPACE,
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.size();
State st = STATE_INITIAL;
for(int i = 0;i < len;i++){
CharType typ = toCharType(s[i]);
if(transfer[st].find(typ) == transfer[st].end()) return false;
else st = transfer[st][typ];
}
return st == STATE_INTEGER||st == STATE_POINT||st == STATE_FRACTION||st == STATE_EXP_NUMBER||st == STATE_END;
}
};