“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),加号 '+' ,减号 '-' ,空格 ' ' 或者点 '.' 。
二、思路分析:
确定有限状态自动机
本题是学习官方题解的确定有限状态自动机方法。首先分析有以下状态:
- 起始的空格
- 符号位
- 整数部分
- 左侧有整数的小数点
- 左侧无整数的小数点
- 小数部分
- 字符 e、E
- 指数部分的符号位
- 指数部分的整数部分
- 末尾的空格
其中 它包含一系列状态,这些状态中:
有一个特殊的状态,被称作「初始状态」。 还有一系列状态被称为「接受状态」,它们组成了一个特殊的集合。其中,一个状态可能既是「初始状态」,也是「接受状态」。比如起始的空格即是初始状态也是接受状态
工作原理
起初,这个自动机处于「初始状态」。随后,它顺序地读取字符串中的每一个字符,并根据当前状态和读入的字符,按照某个事先约定好的「转移规则」,从当前状态转移到下一个状态;当状态转移完成后,它就读取下一个字符。当字符串全部读取完毕后,如果自动机处于某个「接受状态」,则判定该字符串「被接受」;否则,判定该字符串「被拒绝」。
本题若出现的不是数值、e/E、+/-、空格的字符表示为‘null’,因为转移规则没有对应‘null’会立即结束循环
因此根据题目要求确定转移规则,借用官方题解图片
而我的稍有不同,对于如何进行小数部分的循环,我是把 若是判断为小数点无论是哪一种且之后为数值,则转移到左侧有整数的小数点的状态,这样当出现空格、e时对于左侧无整数的小数点状态能进入下一步判断,同时缩减一个表示状态的哈希表
最后如何判断是一个有效的数值呢?最后状态机位于
- 指数部分的整数部分
- 末尾的空格
- 整数部分
- 小数部分即左侧有整数的小数点的状态
表示是一个有效的数值
三、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
};