PROBLEM

剑指 Offer 20. 表示数值的字符串

难度 中等

MY ANSWER

多次提交拼凑出来的答案。

class Solution {
public:
bool isNumber(string s) {
int l = s.find_first_not_of(" ");
if(l == string::npos) {
return false;
}
s.erase(0, l);
int r = s.find_last_not_of(" ");
if(r != string::npos) {
s.erase(r + 1);
}
int point = 0;
int e = 0;
int sign = 0;
int num_ = 0;
int _num = 0;
for(int i = 0; i < s.length(); i++) {
if(isdigit(s[i])) {
if(!point) {
num_++;
}
else {
_num++;
}
continue;
}
switch (s[i]) {
case '.' :
if(point || e) {
return false;
}
else {
if(num_) {
point++;
}
else {
if(i + 1 < s.length() && isdigit(s[i+1])) {
point++;
}
else {
return false;
}
}
}
break;
case '+' :
if(sign || num_ || _num) {
return false;
}
else {
sign++;
}
break;
case '-' :
if(sign || num_ || _num) {
return false;
}
else {
sign++;
}
break;
case 'e' :
if(e || !(num_ + _num)) {
return false;
}
else {
sign = 0;
point = 0;
e++;
num_ = 0;
_num = 0;
}
break;
case 'E' :
if(e || !(num_ + _num)) {
return false;
}
else {
sign = 0;
point = 0;
e++;
num_ = 0;
_num = 0;
}
break;
default :
return false;
}
}
if(!(num_ + _num)) {
return false;
}
if(e) {
if(s.find("e") == s.length() - 1) {
return false;
}
}
return true;
}
};

BETTER SOLUTION

时间复杂度O(n),空间复杂度O(1)。

使用确定有限状态自动机,如图:

fig1

将图使用枚举类型以及哈希表进行实现:

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.length();
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;
}
};

SUMMARY

了解自动机的使用,绘图让问题更清晰,并学习其如何实现。