Skip to main content

65. 有效数字 [hard]

65. 有效数字 [hard]

https://leetcode-cn.com/problems/valid-number/

验证给定的字符串是否可以解释为十进制数字。

例如:

"0" => true
" 0.1 " => true
"abc" => false
"1 a" => false
"2e10" => true
" -90e3 " => true
" 1e" => false
"e3" => false
" 6e-1" => true
" 99e2.5 " => false
"53.5e93" => true
" --6 " => false
"-+3" => false
"95a54e53" => false

说明: 我们有意将问题陈述地比较模糊。在实现代码之前,你应当事先思考所有可能的情况。这里给出一份可能存在于有效十进制数字中的字符列表:

  • 数字 0-9
  • 指数 - "e"
  • 正/负号 - "+"/"-"
  • 小数点 - "."

当然,在输入中,这些字符的上下文也很重要。

  • 更新于 2015-02-10: C++函数的形式已经更新了。如果你仍然看见你的函数接收 const char * 类型的参数,请点击重载按钮重置你的代码。

通过次数16,606 | 提交次数81,816

Second Try

2020-07-29

直接用python的float一波带走,烦恼都没有了。

class Solution:
def isNumber(self, s: str) -> bool:
try:
float(s)
return True
except Exception:
return False
  • 执行用时:44 ms, 在所有 Python3 提交中击败了78.72%的用户
  • 内存消耗:13.6 MB, 在所有 Python3 提交中击败了33.33%的用户

First Try

2020-07-29

用正则解答,但是规则不清晰,浪费太多时间了, f**k.

一开始考虑的规则:

  • 数字不允许0开头,除非是一个0后面跟着小数点
  • 小数点后面必须有数字,小数点前面也必须有数字
  • e前面必须有数字,且不能是小数点

结果这三个规则全部都被破。

特殊case:

  • "0001"是被允许的
  • ".1"是被允许的,"1."也是被允许的,"."不被允许
  • ".1e2"被允许,"1.e2"被允许,".e2"不被允许
  • "e"不被允许, "e1"不被允许, "1e"不被允许
  • " "是错误的

测试案例:

开个shell一遍写正则一遍测试,加快测试速度。

rv =  
['0', '0.1', 'abc', '1 a', '2e10', '-90e3', '1e', 'e3', '6e-1', '99e2.5', '53.5e93', '--6','-+3' '95a54e53']

extra = [
"001",
"1.",
".1",
".1e2",
".e3",
"e",
".",
" ",
"46.e3",
]

解法其实就一条正则,额外考虑" "空白字符串不匹配即可,但是可以看到为了补上那些特殊case,浪费了整整十次提交。

本来想用正则一波带走,没想到浪费了个把小时。。

class Solution:
def isNumber(self, s: str) -> bool:
# 正则表达式一波带走?
# e前面至少有1个数字,因此[0-9]e需要结合在一起
# .后面至少有一个数字,因此.[0-9]+需要结合在一起
# 但这样e和.tmd又冲突了。。。。
import re
# n = "[-|+]?[[[1-9]+[0-9]*]|0][\.[1-9]]?[e[1-9]+]?" # 没有考虑空格挂掉
# n = "\s*[-|+]?(([1-9]+[0-9]*)|0)?(\.[0-9])?(e[-|+]?[1-9]+[0-9]*)?\s*" # 没有考虑001和.1也是允许的,挂掉
# n = "\s*[-|+]?[0-9]*(\.[0-9]+)?[0-9]*([0-9]e[-|+]?[0-9]+)?\s*" # .后面至少1个数字,e前面至少1个数字,同时存在且中间只有1个数字的时候冲突了
# n = "\s*[-|+]?[0-9]*((\.[0-9]+(e[-|+]?[0-9]+)?)|([0-9]+e[-|+]?[0-9]+))?\s*" # 可以简化
# n = "\s*[-|+]?[0-9]*(\.?[0-9]+(e[-|+]?[0-9]+)?)?\s*" # 这个写法空字符串" "也会通过。。。 "3."竟然是允许的,又得剔除了。。。
# 但是 ".1"允许通过, "1."允许通过,结果"."不允许通过。。。
# 关于点的部分拆分成三段,一段:1.; 二段: .2; 三段.1e1 结果1.e1也允许
# n = "\s*[-|+]?[0-9]*(([0-9]+\.)|(\.[0-9]+)|(\.?([0-9]+e[-|+]?[0-9]+)))?\s*" # 46.e3竟然是正确的...
# 继续再考虑".e3"被允许通过的情况, wtf, ".e3"不被允许通过,但是"1.e3"被允许通过
# n = "\s*[-|+]?[0-9]*(([0-9]+\.)|(\.[0-9]+)|(((\.[0-9]*)|([0-9]+))e[-|+]?[0-9]+))?\s*"
# wtf, ".e3"不被允许通过
# n = "\s*[-|+]?[0-9]*(([0-9]+\.)|(\.[0-9]+)|((([0-9]+\.[0-9]*)|([0-9]+))e[-|+]?[0-9]+))?\s*"
# 继续不足"1.e3"要求允许通过
n = "\s*[-|+]?[0-9]*(([0-9]+\.)|(\.[0-9]+)|((([0-9]+\.[0-9]*)|(\.?[0-9]+))e[-|+]?[0-9]+))?\s*"

p = re.compile(n)
rv = re.fullmatch(p, s) # 使用full match才稳妥
if rv:
if len(rv.group().strip()) != 0: # 只剩下空字符串了
return True
return False
  • 执行用时:56 ms, 在所有 Python3 提交中击败了17.46%的用户
  • 内存消耗:13.8 MB, 在所有 Python3 提交中击败了33.33%的用户