【剑指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
列出该矩阵后,我们可以开始简化状态。整个检查流程如下:
  1. 除开转移到自身和转移到对方的那一项状态(如6: 0, 7, 4, 6, 6, 97: 0, 6, 4, 6, 7, 9可以合并),合并其余转移状态完全相同的状态(状态0与状态1,状态4与状态6);
  2. 重复第一条直到没有满足要求的状态。

其实稍微看一下就可以了,有冗余的状态也就输入状态转移方程的时候多打点字。本题删除冗余后的状态为: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。

posted @ 2021-02-25 21:53  tmpUser  阅读(54)  评论(0编辑  收藏  举报