前端刷题路-Day67:有效数字(题号65)| 8月更文挑战

565 阅读3分钟

有效数字(题号65)

题目

有效数字(按顺序)可以分成以下几个部分:

  1. 一个 小数 或者 整数
  2. (可选)一个 'e''E' ,后面跟着一个 整数

小数(按顺序)可以分成以下几个部分:

  1. (可选)一个符号字符('+''-'
  2. 下述格式之一:
    1. 至少一位数字,后面跟着一个点 '.'
    2. 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
    3. 一个点 '.' ,后面跟着至少一位数字

整数(按顺序)可以分成以下几个部分:

  1. (可选)一个符号字符('+''-'
  2. 至少一位数字

部分有效数字列举如下:

  • ["2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"]

部分无效数字列举如下:

  • ["abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]

给你一个字符串 s ,如果 s 是一个 有效数字 ,请返回 true

示例 1

输入:s = "0"
输出:true

示例 2

输入:s = "e"
输出:false

示例 3

输入:s = "."
输出:false

示例 4

输入:s = ".1"
输出:true

提示

  • 1 <= s.length <= 20
  • s 仅含英文字母(大写和小写),数字(0-9),加号 '+' ,减号 '-' ,或者点 '.'

链接

leetcode-cn.com/problems/va…

解释

这题啊,这题是经典排列组合。

为什么说这题是排列组合呢?因为题目已经给的很清楚了:

  • 整数是由数字和符号组成的
  • 小数是由.和有符号和无符号的证书组成的
  • e数是由左侧的小数或者整数和右侧的整数组成的

OK,到了这里,应该可以拆出来三个方法:

  • isInt

    判断是否是整数,这里应该接受两个参数:

    • num

      其实应该是string,也就是主要的字符串

    • withSymbol

      是否带符号,因为有的情况下是只需要整数而不能有符号的

  • isDecimal

    判断是否为小数,只有一个参数,也就是字符串

    将参数按.分割开,比较前面一个值和后面一个值即可

    会利用到isInt函数

  • isE

    判断是否为带e的字符串,只有一个参数,字符串。

    将参数按e分割开,比较前面一个值和后面一个值即可

    会利用到isIntisDecimal函数

接下来只要实现这三个函数,之后按规律调用即可。

这是笔者想出来的答案,并且最后也实现了,虽然代码有点丑陋。

自己的答案(排列组合)

思路上面已经说过了,👇看看代码:

var isNumber = function(s) {
  function isInt(num, withSymbol = true) {
    var numArr = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']
    if (withSymbol) numArr = numArr.concat(['-', '+'])
    for (const char of num) {
      if (!numArr.includes(char)) return false
    }
    return num.length > 0 && Math.floor(num) === +num
  }
  function isDecimal(num) {
    if (['+', '-'].includes(num[0])) {
      num = num.substring(1)
    }
    if (num.includes('.')) {
      var nums = num.split('.')
      if (nums.length > 2) return false
      if (nums[0].length === 0 && nums[1].length === 0) return false
      if (nums[0].length > 0 && !isInt(nums[0])) return false
      if (nums[1].length > 0 && !isInt(nums[1], false)) return false
      return true
    } else {
      return false
    }
  }
  function isE(num) {
    if (num.includes('e')) {
      var nums = num.split('e')
      if (nums.length > 2) return false
      if (!isInt(nums[0]) && !isDecimal(nums[0])) return false
      if (!isInt(nums[1])) return false
      return true
    } else {
      return false
    }
  }
  s = s.toLocaleLowerCase()
  if (s.includes('e')) {
    return isE(s)
  } else if (s.includes('.')) {
    return isDecimal(s)
  } else {
    return isInt(s)
  }
};

代码有点长,请见谅。

说时候,当代码写完的时候下意识感觉肯定不对,因为一般情况下长的代码都是错的,但这次很意外,竟然可以AC,并且不是后5%。

还是按照解释中说的看看这三个函数:

  • isInt

    先搞了一个由字符串数字组组成的数组,之后判断是否有符号,如果有符号就在数组中加上符号,没有就算了。

    然后循环每个字符,判断是否在数组中,不再直接GG。

    最后对长度进行判断,如果长度不对也GG,如果是小数也GG。

  • isDecimal

    首先第一步,去掉开头的符号。

    接下来按照.来分割字符串,由题意可以得到这几种组合条件。

    • .前后必须有一个值
    • .前面的值可以是带符号的数字
    • .后面的值只能是数字

    之后就是简单的进行判断了,如果结果都通过了就是true,否则是false

  • isE

    isEisDecimal类似,也是分割开来进行条件处理,逻辑相对于isDecimal简单一些。

最后先将字符串转换成全小写的,防止E的出现。

之后如果有e就走isE,如果有.就走isDecimal,如果都没有就走isInt,这就完事了。

整体还是比较简单的,只是过程当中需要注意特殊情况,好在题目中已经列出了大部分特殊情况了,能跑通基本上就差不多了。

更好的方法(一步到位)

这个方法就有点投机倒把的意思了,利用isNaNInfinity一波组合判断解决问题。

var isNumber = function(s) {
    if(s==="Infinity"||s==="-Infinity"||s==="+Infinity") return false
    return !isNaN(s)
};

性能那是没话说啊,毕竟是JavaScript原生的方法,执行时间直接干到100%了。

更好的方法(状态机)

说时候,这块笔者没看懂,有点太过于深入的感觉,即使看懂了估计后来也会忘,直接放弃,有兴趣的同学可以看看官方的解释,十分详细:点击这里跳转官方答案



PS:想查看往期文章和题目可以点击下面的链接:

这里是按照日期分类的👇

前端刷题路-目录(日期分类)

经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇

前端刷题路-目录(题型分类)