文章目录
- 题目链接
- 标签
- 步骤
- 实现代码(C++)
题目链接
剑指 Offer 20. 表示数值的字符串
标签
有限状态自动机(FA)
步骤
Step1. 去除字符串左、右空格;
string strip(string str) {
int start = -1;
for (int i = 0; i < str.length(); i++) {
if (str[i] != ' ') {
start = i;
break;
}
}
if (start == -1) return str;
int end = -1;
for (int i = str.length() - 1; i >= 0; i--) {
if (str[i] != ' ') {
end = i;
break;
}
}
return str.substr(start, end - start + 1);
}
Step2. 写出正规文法:
S
→
(
+
∣
−
∣
ϵ
)
(
I
N
T
∣
F
L
O
A
T
)
E
X
P
I
N
T
→
d
i
g
i
t
(
d
i
g
i
t
)
∗
F
L
O
A
T
→
d
i
g
i
t
(
d
i
g
i
t
)
∗
.
(
d
i
g
i
t
)
∗
∣
.
d
i
g
i
t
(
d
i
g
i
t
)
∗
E
X
P
→
(
+
∣
−
∣
ϵ
)
I
N
T
∣
ϵ
\mathrm{S}\rightarrow (+|-|\mathrm{\epsilon )(INT}|\mathrm{FLOAT)EXP} \\ \mathrm{INT}\rightarrow \mathrm{digit(digit)}^* \\ \mathrm{FLOAT}\rightarrow \mathrm{digit(digit)}^*.(\mathrm{digit)}^*|.\mathrm{digit(digit)}^* \\ \mathrm{EXP}\rightarrow (+|-|\mathrm{\epsilon )INT}|\mathrm{\epsilon}
S→(+∣−∣ϵ)(INT∣FLOAT)EXPINT→digit(digit)∗FLOAT→digit(digit)∗.(digit)∗∣.digit(digit)∗EXP→(+∣−∣ϵ)INT∣ϵ
Step3. 根据正规文法画出NFA:
Step4. 根据NFA写代码:从左至右遍历,遇到包含ε的转移,单独处理。遍历完成后,看状态是否为终态(2、4、7),是则返回 true,否则 false。
for (int i = 0; i < str.length(); i++) {
char ch = str[i];
switch (state) {
case 0:
if (isFlag(ch)) {
state = 1;
} else {
state = 1;
i--; // 处理ε情况,i--
}
break;
case 1:
if (isDigit(ch)) {
state = 2;
} else if (ch == '.') {
state = 3;
} else {
return false;
}
break;
case 2:
if (isDigit(ch)) {
state = 2;
} else if (ch == '.') {
state = 4;
} else if (ch == 'e' || ch == 'E') {
state = 5;
} else {
return false;
}
break;
case 3:
if (isDigit(ch)) {
state = 4;
} else {
return false;
}
break;
case 4:
if (isDigit(ch)) {
state = 4;
} else if (ch == 'e' || ch == 'E') {
state = 5;
} else {
return false;
}
break;
case 5:
if (isFlag(ch)) {
state = 6;
} else {
state = 6;
i--; // 处理ε情况,i--
}
break;
case 6:
if (isDigit(ch)) {
state = 7;
} else {
return false;
}
break;
case 7:
if (isDigit(ch)) {
state = 7;
} else {
return false;
}
break;
}
}
实现代码(C++)
class Solution {
public:
string strip(string str) {
int start = -1;
for (int i = 0; i < str.length(); i++) {
if (str[i] != ' ') {
start = i;
break;
}
}
if (start == -1) return str;
int end = -1;
for (int i = str.length() - 1; i >= 0; i--) {
if (str[i] != ' ') {
end = i;
break;
}
}
return str.substr(start, end - start + 1);
}
bool isDigit(char c) {
if (c >= '0' && c <= '9') {
return true;
}
return false;
}
bool isFlag(char c) {
if (c == '+' || c == '-') {
return true;
}
return false;
}
bool isNumber(string s) {
int len = s.length();
// step 1/4:去除首尾空格
string str = strip(s);
int state = 0;
for (int i = 0; i < str.length(); i++) {
char ch = str[i];
switch (state) {
case 0:
if (isFlag(ch)) {
state = 1;
} else {
state = 1;
i--;
}
break;
case 1:
if (isDigit(ch)) {
state = 2;
} else if (ch == '.') {
state = 3;
} else {
return false;
}
break;
case 2:
if (isDigit(ch)) {
state = 2;
} else if (ch == '.') {
state = 4;
} else if (ch == 'e' || ch == 'E') {
state = 5;
} else {
return false;
}
break;
case 3:
if (isDigit(ch)) {
state = 4;
} else {
return false;
}
break;
case 4:
if (isDigit(ch)) {
state = 4;
} else if (ch == 'e' || ch == 'E') {
state = 5;
} else {
return false;
}
break;
case 5:
if (isFlag(ch)) {
state = 6;
} else {
state = 6;
i--;
}
break;
case 6:
if (isDigit(ch)) {
state = 7;
} else {
return false;
}
break;
case 7:
if (isDigit(ch)) {
state = 7;
} else {
return false;
}
break;
}
}
string finalState = "247";
return finalState.find(state+'0', 0) == string::npos ? false : true;
}
};