LeetCode打卡day4

106 阅读1分钟

“Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。”

一、题目描述:

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

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

若干空格

一个 小数 或者 整数

(可选)一个 '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),加号 '+' ,减号 '-' ,空格 ' ' 或者点 '.' 。

二、思路分析:

确定有限状态自动机

本题是学习官方题解的确定有限状态自动机方法。首先分析有以下状态:

  1. 起始的空格
  2. 符号位
  3. 整数部分
  4. 左侧有整数的小数点
  5. 左侧无整数的小数点
  6. 小数部分
  7. 字符 e、E
  8. 指数部分的符号位
  9. 指数部分的整数部分
  10. 末尾的空格

其中 它包含一系列状态,这些状态中:

有一个特殊的状态,被称作「初始状态」。 还有一系列状态被称为「接受状态」,它们组成了一个特殊的集合。其中,一个状态可能既是「初始状态」,也是「接受状态」。比如起始的空格即是初始状态也是接受状态

工作原理

起初,这个自动机处于「初始状态」。随后,它顺序地读取字符串中的每一个字符,并根据当前状态和读入的字符,按照某个事先约定好的「转移规则」,从当前状态转移到下一个状态;当状态转移完成后,它就读取下一个字符。当字符串全部读取完毕后,如果自动机处于某个「接受状态」,则判定该字符串「被接受」;否则,判定该字符串「被拒绝」。

本题若出现的不是数值、e/E、+/-、空格的字符表示为‘null’,因为转移规则没有对应‘null’会立即结束循环

因此根据题目要求确定转移规则,借用官方题解图片

image.png

而我的稍有不同,对于如何进行小数部分的循环,我是把 若是判断为小数点无论是哪一种且之后为数值,则转移到左侧有整数的小数点的状态,这样当出现空格、e时对于左侧无整数的小数点状态能进入下一步判断,同时缩减一个表示状态的哈希表

最后如何判断是一个有效的数值呢?最后状态机位于

  1. 指数部分的整数部分
  2. 末尾的空格
  3. 整数部分
  4. 小数部分即左侧有整数的小数点的状态

表示是一个有效的数值

三、AC 代码:

 * @param {string} s
 * @return {boolean}
 */
var isNumber = function (s) {
    const map=[
        new Map([[' ',0],['signal',1],['digital',2],['.',4]]),//开头空格
        new Map([['digital',2],['.',4]]),                     //+-
        new Map([['digital',2],['.',3],['e',5],[' ',8]]),//digital
        new Map([['digital',3],['e',5],[' ',8]]),//.前有数值
        new Map([['digital',3]]),//.前no数值
        new Map([['signal',6],['digital',7]]),//e
        new Map([['digital',7]]),//+-
        new Map([['digital',7],[' ',8]]),//digital
        new Map([[' ',8]])
    ]
    let state=0,convert
    for(let i of s){
        if(i===' '||i==='.')convert=i
        else if(i>='0'&&i<='9')convert='digital'
        else if(i.toLowerCase()==='e')convert='e'
        else if(i==="+"||i==="-")convert='signal'
        else convert='null'
        if(map[state].has(convert)){
            state=map[state].get(convert)
        }else return false;

    }
    return state===8||state===2||state===3||state===7
};