【LeetCode】【剑指offer】【表示数值的字符串】

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

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。

数值(按顺序)可以分成以下几个部分:

若干空格
一个 小数 或者 整数
(可选)一个 'e' 或 'E' ,后面跟着一个 整数
若干空格
小数(按顺序)可以分成以下几个部分:

(可选)一个符号字符('+' 或 '-')
下述格式之一:
至少一位数字,后面跟着一个点 '.'
至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
一个点 '.' ,后面跟着至少一位数字
整数(按顺序)可以分成以下几个部分:

(可选)一个符号字符('+' 或 '-')
至少一位数字
部分数值列举如下:

["+100", "5e2", "-123", "3.1416", "-1E-16", "0123"]
部分非数值列举如下:

["12e", "1a3.14", "1.2.3", "+-5", "12e+5.4"]
 

示例 1:

输入:s = "0"
输出:true
示例 2:

输入:s = "e"
输出:false
示例 3:

输入:s = "."
输出:false
示例 4:

输入:s = "    .1  "
输出:true
 

提示:

1 <= s.length <= 20
s 仅含英文字母(大写和小写),数字(0-9),加号 '+' ,减号 '-' ,空格 ' ' 或者点 '.' 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/biao-shi-shu-zhi-de-zi-fu-chuan-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

本题使用有限状态自动机。根据字符类型和合法数值的特点,先定义状态,再画出状态转移图,最后编写代码即可。

字符类型:

空格 「 」、数字「0—9」、正负号「+-」、小数点「.」、幂符号「eE」

状态定义:

按照字符串从左到右的顺序,定义以下 9 种状态。

0、开始的空格
1、幂符号前的正负号
2、小数点前的数字
3、小数点、小数点后的数字
4、当小数点前为空格时,小数点、小数点后的数字
5、幂符号
6、幂符号后的正负号
7、幂符号后的数字
8、结尾的空格
结束状态:

合法的结束状态有 2, 3, 7, 8 。

算法流程:

1.初始化:

        1.状态转移表state:设state[i],其中i为所处的状态,state[i]使用哈希表存储可转移至状态。键值对(key,value)含义:若输入key,则可以从状态i转移至状态value

        2.当前状态p:起始状态初始化为p=0

2.状态转移循环:遍历字符串s的每个字符c

        1.记录字符类型t:分为四种情况

                当c为正负号时,执行t='s';

                当c为数字时,执行t='d';

                当c为e或者E时,执行t='e'

                当c为  .   或者空格时执行t=c(即用字符本身表示字符类型);

                否则,执行t='?',代表为不属于判断范围的非法字符,后续直接返回false

        2.终止条件:若字符类型t不再哈希表states[p]中,说明无法转移至下一状态,因此直接返回false

        3.状态转移:状态p转移至states[p][t].

3.返回值:跳出循环后,若状态p属于2,3,7,8,说明结尾合法,范湖true,否则返回false

class Solution {
public:
    //创建一个char和int的组合
    typedef pair<char, int> charint;
    //创建一个无序的映射map
    typedef unordered_map<char,int> unmap;
    bool isNumber(string s) {
        //创建一个容器,其中的每一个元素都是unmap也就是一个无序的<char,int>映射
        vector<unmap> states = {
            // s表示符号,d表示数字,e表示e或E
            //下面的' ',0表示可以通过空格转换到后面的状态0,以此类推
            //这是第0种状态,也就是起始的空格状态
            //第0种状态可以转换到第0种状态,第一种状态,第二种状态或者第四种状态
            unmap{charint(' ', 0), charint('s', 1), charint('d', 2), charint('.', 4)},
            //这是第1种状态,也就是e之前的sign状态
            //第一种状态可以转换到第二种状态和第四种状态
            unmap{charint('d', 2), charint('.', 4)},
            //这是第2种状态,也就是点之前的数字状态
            //第二种状态可以转换到第二种状态,第三种状态,第五种状态,或者是第8种状态
            unmap{charint('d', 2), charint('.', 3), charint('e', 5), charint(' ', 8)},
            //这是第3种状态,也就是点之后的数字状态
            //第三种状态可以转换到第三种状态,第五种状态,或者第八种状态
            unmap{charint('d', 3), charint('e', 5), charint(' ', 8)},
            //这里是第4种状态,也就是当点之前为空时,点之后的数字的状态
            //第四种状态可以转换到第三种状态
            unmap{charint('d', 3)},
            //这里是第5种状态,也就是e的状态
            //第五种状态可以切换到第六种状态或者是第七种状态
            unmap{charint('s', 6), charint('d',7)},
            //这里是第6种状态,也就是e之后的符号状态
            //第六种状态可以转换到第7种状态
            unmap{charint('d', 7)},
            //这里是第7种状态,也就是e之后的数值状态
            //第七种状态可以转换到第七种状态或者是第八种状态
            unmap{charint('d', 7), charint(' ',8)},
            //这里是第8种状态,也就是结尾的空格状态
            //第八种状态只能转换到第八种状态
            unmap{charint(' ', 8)}
        };
        //初始是第0种状态
        int p = 0;
        //用t判断我们当前处于那种状态
        char t;
        for(char c : s){
            //处于数字状态d
            if(c >= '0' && c <= '9')
                t = 'd';
            //处于符号状态s
            else if(c == '+' || c == '-')
                t = 's';
            //处于e状态
            else if(c == 'e' || c == 'E')
                t = 'e';
            //处于点或者空格状态
            else if(c == '.' || c == ' ')
                t = c;
            else
            //不处于任何一种状态的时候就将t标志为?
                t = '?';
            // 无下一个转移状态
            //从当前的p状态中统计是否有转移到't'的方法
            if(!states[p].count(t)){
                return false;
            }
            //转换到下一个状态
            //更新我们的p状态,也就是我们的states[p]也就是当前状态中t所对应的状态。
            p = (int)states[p][t];
        }
        //只要p是以状态2,3,7,8作为结束的都是可行的
        return p == 2 || p == 3 || p == 7 || p == 8;
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值