请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
数值(按顺序)可以分成以下几个部分:
若干空格
一个 小数 或者 整数
(可选)一个 '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;
}
};