题目描述

Validate if a given string can be interpreted as a decimal number.

Here is a list of characters that can be in a valid decimal number:
Numbers: 0-9
Exponent: "e"
Positive/negative sign: "+"/"-"
Decimal point: "."

Some examples:
"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

解题思路

题目的意思是判断一个字符串是否是一个有效的数字,我觉得首先是要明确什么是一个有效的数字,题目说的比较含糊,只是给了几个例子。根据我的尝试,总结了一下有效数字的定义。
这里有效的数字是一个实数,而且满足下面的结构定义:

# Realnum : (SignDec)e(Integer) | SignDec
# SignDec : -(Decimal) | +(Decimal) | Decimal
# Decimal : (Primary).(Primary) | (Primary) | .(Primary) | (Primary).
# Integer : -(Primary) | +(Primary) | Primary
# Primary : Numbers | (Numbers)(Primary)
# Numbers : 0 | 1 | ... | 9 |

格式上有一些乱,主要是一些关系不好表示,解释一下
1. 一个十进制实数要么是带指数或者是一个带符号的小数
eg: -23e-4, 4e3, -3.23
2. 一个带符号小数是一个带'+'号或者'-'号的小数,或者不带符号的小数
eg: +34.34, -435.1, 342
3. 一个小数是两个无符号整数之间加一个小数点'.'构成,或者一个无符号整数(Primary),或者省略小数点前后的0
eg: 0.1234, .12(等于0.12), 45.1, 4.(等于4.0)
4. 一个有符号整数是一个带'+'号或者'-'号的无符号整数,或者不带符号,其实这个定义包含在了小数中,但是因为指数格式不能是小数,为了方便所以还需要一个单独的定义
eg: +12, -34, 56
5. 一个无符号整数是由数字序列构成的,这里省略了无符号整数的定义。
eg: 32, 324, 897
6. 数字序列要么是一个数字,或者一个数字加上一个数字序列,是一个递归定义
eg: 3, 5, 9, 2, 3454, 1212

根据这个实数的定义,可以比较简单写出判断有效数字的算法,这里的算法实现使用的语言是python3,因为python的字符串相对与C/C++容易操作,从而可以更好地体现算法的思想,而不必关注太多的细节。

算法实现

根据有效的数字的结构,逐层分解字符串,来判断是否满足该结构。要注意的是需要要去除字符串首部和尾部的空白符。
这道题在leetcode上,使用的上面的程序结构。

class Solution:
    def isNumber(self, s: str) -> bool:
        ## 判断是否是一个有效的数字
        def Realnum(numstr):
            if numstr == '':
                return False
            index = numstr.find('e')
            if index == -1:
                return Sign(numstr, 1)
            elif index == 0 or index == len(numstr)-1:
                return False
            else:
                return Sign(numstr[:index], 1) and Sign(numstr[index+1:], 0)
        ## 判断带符号数字,根据mode来确定是小数还是整数
        def Sign(numstr, mode):
            i = 0
            if numstr[i] == '+' or numstr[i] == '-':
                i += 1
            if mode == 0:
                return Primary(numstr[i:])
            else:
                return Decimal(numstr[i:])
        ## 判断无符号小数
        def Decimal(numstr):
            index = numstr.find('.')
            if index == -1:
                return Primary(numstr)
            elif index == 0:
                return Primary(numstr[index+1:])
            elif index == len(numstr)-1:
                return Primary(numstr[:index])
            else:
                return Primary(numstr[:index]) and Primary(numstr[index+1:])
        ## 判断是否是数字序列
        def Primary(numstr):
            return numstr.isnumeric()

        ## 忽略串尾和串头的空格
        s = s.lstrip()
        s = s.rstrip()
        return Realnum(s)
  1. Realnum
    对于一个字符串s,首先在串s中查找指数字符'e'
    如果没有查找到,那么判断是否是一个带符号小数
    否则,判断找到的下标index
    如果index不是第一个或者最后一个位置,判断字符'e'之前的子串是否为一个带符号小数,'e'之后的串是否为一个带符号整数

  2. Sign
    将串前面的符号去掉,然后将参数送往不同的处理函数中:无符号小数或者无符号整数

  3. Decimal
    对于已经分解好的字符串,在串中查找小数点符号'.',根据查找的结果(小数点的位置),来处理去掉小数点后的子串