【剑指Offer-20】表示数值的字符串
问题
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
示例
字符串"+100"、"5e2"、"-123"、"3.1416"、"-1E-16"、"0123"都表示数值,
但"12e"、"1a3.14"、"1.2.3"、"+-5"及"12e+5.4"都不是。
解答1:确定有限状态自动机(DFA)
class Solution {
public:
bool isNumber(string s) {
int tansfer[9][5] = { // 状态转移矩阵
{0, 1, 2, 4, -1},
{-1, -1, 2, 4, -1},
{8, -1, 2, 3, 5},
{8, -1, 3, -1, 5},
{-1, -1, 3, -1, -1},
{-1, 6, 7, -1, -1},
{-1, -1, 7, -1, -1},
{8, -1, 7, -1, -1},
{8, -1, -1, -1, -1}
};
int state = 0; // 初始状态
for (char i : s) { // 遍历输入字符串
if (i == ' ') state = tansfer[state][0];
else if (i == '+' || i == '-') state = tansfer[state][1];
else if (isdigit(i)) state = tansfer[state][2];
else if (i == '.') state = tansfer[state][3];
else if (i == 'e' || i == 'E') state = tansfer[state][4];
else state = -1;
if (state == -1) return false; // 遇到错误状态立即返回false
}
return state == 2 || state == 3 || state == 7 || state == 8 ; // 满足几个正确的最终状态则返回true
}
};
重点思路
本题使用有限状态自动机。根据字符类型和合法数值的特点,先定义每个字符输入前的状态,再作出状态转移矩阵,最后编写代码即可。
根据题目给出的示例以及一些尝试,需要特别注意的要求有:
- 前后可以有任意数量空格;
- 小数点前后至少有一处有数值;
- E、e后不允许存在小数。
根据以上要求,我们列举一个尽可能复杂的满足要求的字符串+1.2E-2
,参考这个字符串开始定义状态,这个阶段不需要考虑状态冗余的问题。我们不仅需要把不同字符类型定义为不同状态,还需要把相同类型但在不同前后文状态的字符定义为不同状态。例如上述例子中,1.2
与-2
都表示数字,但E前后对数字的要求是不同的,不能简单地定义为一个状态。另外,小数点前后的数字也不能定义为一个状态。同理,小数点前是否存在数字也对后续状态有影响(例如1.
可以,.
不行)。
根据以上结论,此题所有状态的定义是:0.初始状态;1.前空格;2.E、e前的正负号;3.小数点前的数;4.前面有数字的小数点;5.前面没数字的小数点;6.小数点后的数字;7.E、e;8.E、e后的正负号;9.E后的数字;10.后空格。
我们建立以上状态对应的转移矩阵:
空格 | +、- | 数字 | 小数点 | E、e | |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 5 | -1 |
1 | 1 | 2 | 3 | 5 | -1 |
2 | -1 | -1 | 3 | 5 | -1 |
3 | 10 | -1 | 3 | 4 | 7 |
4 | 10 | -1 | 6 | -1 | 7 |
5 | -1 | -1 | 6 | -1 | -1 |
6 | 10 | -1 | 6 | -1 | 7 |
7 | -1 | 8 | 9 | -1 | -1 |
8 | -1 | -1 | 9 | -1 | -1 |
9 | 10 | -1 | 9 | -1 | -1 |
10 | 10 | -1 | -1 | -1 | -1 |
列出该矩阵后,我们可以开始简化状态。整个检查流程如下: |
- 除开转移到自身和转移到对方的那一项状态(如
6: 0, 7, 4, 6, 6, 9
与7: 0, 6, 4, 6, 7, 9
可以合并),合并其余转移状态完全相同的状态(状态0与状态1,状态4与状态6); - 重复第一条直到没有满足要求的状态。
其实稍微看一下就可以了,有冗余的状态也就输入状态转移方程的时候多打点字。本题删除冗余后的状态为:0.初始状态或前空格;1.E、e前的正负号;2.小数点前的数;3.前面有数字的小数点;4.前面没数字的小数点或者小数点后的数字;5.E、e;6.E、e后的正负号;7.E后的数字;8.后空格。最终得到的状态转移矩阵为:
空格 | +、- | 数字 | 小数点 | E、e | |
---|---|---|---|---|---|
0 | 0 | 1 | 2 | 4 | -1 |
1 | -1 | -1 | 2 | 4 | -1 |
2 | 8 | -1 | 2 | 3 | 5 |
3 | 8 | -1 | 3 | -1 | 5 |
4 | -1 | -1 | 3 | -1 | -1 |
5 | -1 | 6 | 7 | -1 | -1 |
6 | -1 | -1 | 7 | -1 | -1 |
7 | 8 | 8 | 9 | -1 | -1 |
8 | 8 | -1 | 9 | -1 | -1 |
最后,我们需要确定哪些状态可以用来当最终状态。本题可以作为最终状态的为2、3、7、8。