剑指 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),加号 '+' ,减号 '-' ,空格 ' ' 或者点 '.' 。
解题思路 : 哈希表+有限状态机
对于一个要表示数值的有固定格式的字符串,显然每个字符的取值不外乎以下几种有限的状态
- 开头的空格
- e/E之前的符号位
- 前面有数字的小数点
- 小数点前的数字
- 小数点后的数字
- e、E
- e之后的符号位
- e之后的数字
- 结束的空格
- 前面没有数字的小数点
构建的有限状态机如下:
对于遍历的每一个字符,都设定好其可能的下一步状态,如果下一个字符不属于这个状态,返回false,直到遍历完成。如果最终状态是3、4、5、8、9状态是正确的,返回true,否则返回false
代码
class Solution {
public boolean isNumber(String s) {
Map[] maps = {
new HashMap(){{put(' ',0);put('s',1);put('p',9);put('n',3);}},
new HashMap(){{put('p',9);put('n',3);}},
new HashMap(){{put('n',4);put(' ',8);put('e',5);}},
new HashMap(){{put('n',3);put('p',2);put('e',5);put(' ',8);}},
new HashMap(){{put('n',4);put('e',5);put(' ',8);}},
new HashMap(){{put('s',6);put('n',7);}},
new HashMap(){{put('n',7);}},
new HashMap(){{put('n',7);put(' ',8);}},
new HashMap(){{put(' ',8);}},
new HashMap(){{put('n',4);}}
};
int i = 0 ;
char flag = ' ';
for(char c : s.toCharArray())
{
if(c>='0'&&c<='9')
{
flag = 'n';
}else if(c==' ')
{
flag = ' ';
}else if(c=='.')
{
flag = 'p';
}else if(c=='+'||c=='-')
{
flag = 's';
}else if(c=='e'||c=='E')
{
flag = 'e';
}else{
return false;
}
if(!maps[i].containsKey(flag)) return false;
i = (int)maps[i].get(flag);
}
return i==3||i==4||i==7||i==8||i==2;
}
}
算法执行过程
- 初始化
- 状态转移映射 map[] , i 表示第i+1个状态,map[i]表示第i个状态的合法下一个状态的集合,形式为键值对 <Character,Integer> ,输入标识符,返回下一个状态
- 当前状态 i : 初始状态初始化为i=0,表示第一个状态(开头空格)
- 状态转移循环
- 记录字符类型 : 字符flag为下一个字符所表示的状态,分为以下6种情况:
- 字符c>‘0’&&flag<‘9’ , flag = ‘n’(number)
- 字符c==’ ’ , flag = ’ ’
- 字符c==’.’ , flag = ‘p’(point)
- 字符c== ‘+’ ||c == ‘-’ , flag = ‘s’(signal)
- 字符c== ‘e’ || c== ‘E’ , flag = ‘e’
- 其他直接返回false
- 终止条件 : 如果flag不在 哈希映射表map中,则说明无法转移到下一个状态,直接返回false
- 返回值 : 跳出循环之后,如果状态 i == 2、3、4、7、8,则说明结果合法,返回true
- 记录字符类型 : 字符flag为下一个字符所表示的状态,分为以下6种情况: