思路一
作弊法:利用try…except机制,直接判断是否可以通过float()函数
class Solution:
def isNumber(self, s: str) -> bool:
try:
float(s)
return True
except:
return False
面试的时候这么写基本byebye
思路二
设置几个布尔值:dot_seen = False
,e_seen = False
,num_seen = False
,分别代表该类型的值是否已经出现过
利用s.strip()函数将s两边的空格去掉,然后遍历,根据当前元素的类型,将不是有效数字的情况列出,return False:
- 当前元素为数字,那么下一个元素是什么类型都可以,所以只要digit_seen变为True;
- 当前元素为e,如果之前已经出现过e,或者没有出现过数字,那么不是有效数字,False;
- 当前元素是小数点,如果之前已经出现过小数点或者e,那么不是有效数字,False;
- 当前元素是正负号,如果该元素不是首位,且前一个元素不是e,那么肯定不是有效数字,False。
代码
class Solution:
def isNumber(self, s: str) -> bool:
s = s.strip()
dot_seen = False
e_seen = False
num_seen = False
for i,a in enumerate(s):
if a.isdigit():
num_seen = True
elif a == '.':
if dot_seen or e_seen:
return False
dot_seen = True
elif a == 'e':
if e_seen or not num_seen:
return False
e_seen = True
num_seen = False #因为e之后必须再次判断是否出现数字,所以这里要把num_seen置为False
elif a in '+-':
if i > 0 and s[i-1] != 'e':
return False
else:
return False
return num_seen
思路三
有限自动机法
我理解了一下,就是判断状态是否可以转移,最终是否能转移到合格的状态上,如图:
- 画出状态转移表,结构为states[n]存储n个状态;
- states[i]为一个HashTable,表示从此状态允许跳转到的状态;
- 主循环中遍历字符串,通过状态转移表判断结构是否成立:
若中途遇到无法跳转的状态,直接返回False;
若成功遍历完字符串,要判断结束状态是否在允许的结束状态内,本题为[3, 5, 8, 9]。
代码
class Solution:
def isNumber(self, s: str) -> bool:
state = [
{},
# 状态1,初始状态(扫描通过的空格)
{"blank": 1, "sign": 2, "digit": 3, ".": 4},
# 状态2,发现符号位(后面跟数字或者小数点)
{"digit": 3, ".": 4},
# 状态3,数字(一直循环到非数字)
{"digit": 3, ".": 5, "e": 6, "blank": 9},
# 状态4,小数点(后面只有紧接数字)
{"digit": 5},
# 状态5,小数点之后(后面只能为数字,e,或者以空格结束)
{"digit": 5, "e": 6, "blank": 9},
# 状态6,发现e(后面只能符号位, 和数字)
{"sign": 7, "digit": 8},
# 状态7,e之后(只能为数字)
{"digit": 8},
# 状态8,e之后的数字后面(只能为数字或者以空格结束)
{"digit": 8, "blank": 9},
# 状态9, 终止状态 (如果发现非空,就失败)
{"blank": 9}
]
cur_state = 1
for i in s:
if i.isdigit():
i = 'num'
elif i == '.':
i = 'dot'
elif i in '+-':
i = 'sign'
elif i == ' ':
i = 'blank'
elif i == 'e':
i = 'e'
if i not in state[cur_state]:
return False
cur_state = state[cur_state][i]
return cur_state in [3,5,8,9]