65. 有效数字


一、题目

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

例如:

"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 * 类型的参数,请点击重载按钮重置你的代码。

二、思路

1. 正则

作为有效的十进制数字,必然是以+-开头,+号在数为非负的时候是可以不写的,所以可以得出正则表达式第一部分:^[+-]?

对于科学计数法,指数e是在小数点后边的,所以接下来就是小数点问题:

  • 例如:.5这个数,对应的正则表达式则是:\.\d+
  • 例如:5.这个数,对应的正则表达式则是:\d+
  • 例如:4.5这个数,对应正则表达式则是:\d+\.\d+
  • 例如:5这个数,是没有小数点的,对应正则表达式是:\d+
  • 所以,综合以上几种情况,第二部分的正则表达式为:(\d+|\d+\.|\d+\.\d+|\.\d+)

接下来便是科学计数法部分了,因为指数e不一定存在,所以正则表达式是:(e[+-]?\d+)?

到这里就结束了,所以整体的正则表达式是:^[+-]?(\d+|\d+\.|\d+\.\d+|\.\d+)(e[+-]?\d+)?$

2. 条件判断

对于这道题,通过题目所提供的信息,我们可以对以下几个条件进行判断:

  • 首先就是+-,这两个符号出现的位置有两个:
    • 数字开头
    • 指数e的后边,紧接着e出现
  • 接下来就是小数点了,并且小数点一定是在指数e的前边的。所以
    • 当前值为小数点的时候,e必须还没有出现过
    • 小数点只能出现一次
  • 接下来判断e
    • e只能出现一次
    • 并且e的出现之前必须存在数字
    • e出现一次以后。也必须有数字存在

根据上边的条件限定,我们假设字符串长度为n(使用strip()去掉两侧空格以后),当前元素下标为i,接下来就该考虑在代码中的实现了。

对于+-我们需要做的是对其位置进行判断:

  • 第一种情况就是i == 0
  • 第二种情况就是i != 0 and s[i] == 'e',如果s[i] != 'e',那么就可以返回False

接下来,小数点.,我们就需要对小数点和指数e的出现状态进行判断了。我们可以创建两个变量dote分别来保存它们的出现状态,初始值都设为False,表示还没有出现。出现以后,值改为True

接下来就是e,这时候需要判断的是e的出现状态,以及num_pre_e就是在e之前是否有数字出现。以及num_after_e也就是在e之后是否有数字出现。并且在s[i] == 'e'的时候,需要将num_after_e的值重置为False

接下来,在判断s[i].isdigit() is True的情况下,将num_after_e的值重置为True。并且,在e is Flase的条件下,num_pre_e的值才为True

三、代码

1. 正则

import re

class Solution:
    def isNumber(self, s: str) -> bool:
        pattern = re.compile(r'^[+-]?(\d+\.\d+|\d+\.|\.\d+|\d+)(e[+-]?\d+)?$')
        res = pattern.findall(s.strip(' '))
        return True if len(res) > 0 else False

2. 条件判断

# 点、指数e、e后边的数字、e前边的数字
dot, e, num_after_e, num_pre_e = False, False, False, False

        s = s.strip(' ')
        n = len(s)
        for i in range(n):
            if s[i] in ['+', '-']:
                if i != 0 and s[i-1] != 'e':
                    return False
            elif s[i] == '.':
                if dot or e:
                    return False
                else:
                    dot = True
            elif s[i] == 'e':
                if e or not num_pre_e:
                    return False
                else:
                    e = True
                    num_after_e = False
            elif s[i].isdigit():
                if not e:
                    num_pre_e = True
                num_after_e = True
            else:
                return False
        return num_after_e and num_pre_e

四、表现

method 运行时间 表现 内存消耗 表现
1. 正则 48ms 55.48% 13.6MB 5.03%
2. 条件判断 48ms 55.48% 13.5MB 10.19%

文章作者: Arvin He
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Arvin He !
评论
  目录