有效数字(题号65)
题目
有效数字(按顺序)可以分成以下几个部分:
- 一个 小数 或者 整数
- (可选)一个
'e'或'E',后面跟着一个 整数
小数(按顺序)可以分成以下几个部分:
- (可选)一个符号字符(
'+'或'-') - 下述格式之一:
- 至少一位数字,后面跟着一个点
'.' - 至少一位数字,后面跟着一个点
'.',后面再跟着至少一位数字 - 一个点
'.',后面跟着至少一位数字
- 至少一位数字,后面跟着一个点
整数(按顺序)可以分成以下几个部分:
- (可选)一个符号字符(
'+'或'-') - 至少一位数字
部分有效数字列举如下:
["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 <= 20s仅含英文字母(大写和小写),数字(0-9),加号'+',减号'-',或者点'.'。
链接
解释
这题啊,这题是经典排列组合。
为什么说这题是排列组合呢?因为题目已经给的很清楚了:
- 整数是由数字和符号组成的
- 小数是由
.和有符号和无符号的证书组成的 e数是由左侧的小数或者整数和右侧的整数组成的
OK,到了这里,应该可以拆出来三个方法:
-
isInt判断是否是整数,这里应该接受两个参数:
-
num其实应该是string,也就是主要的字符串
-
withSymbol是否带符号,因为有的情况下是只需要整数而不能有符号的
-
-
isDecimal判断是否为小数,只有一个参数,也就是字符串
将参数按
.分割开,比较前面一个值和后面一个值即可会利用到
isInt函数 -
isE判断是否为带
e的字符串,只有一个参数,字符串。将参数按
e分割开,比较前面一个值和后面一个值即可会利用到
isInt和isDecimal函数
接下来只要实现这三个函数,之后按规律调用即可。
这是笔者想出来的答案,并且最后也实现了,虽然代码有点丑陋。
自己的答案(排列组合)
思路上面已经说过了,👇看看代码:
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。 -
isEisE和isDecimal类似,也是分割开来进行条件处理,逻辑相对于isDecimal简单一些。
最后先将字符串转换成全小写的,防止E的出现。
之后如果有e就走isE,如果有.就走isDecimal,如果都没有就走isInt,这就完事了。
整体还是比较简单的,只是过程当中需要注意特殊情况,好在题目中已经列出了大部分特殊情况了,能跑通基本上就差不多了。
更好的方法(一步到位)
这个方法就有点投机倒把的意思了,利用isNaN和Infinity一波组合判断解决问题。
var isNumber = function(s) {
if(s==="Infinity"||s==="-Infinity"||s==="+Infinity") return false
return !isNaN(s)
};
性能那是没话说啊,毕竟是JavaScript原生的方法,执行时间直接干到100%了。
更好的方法(状态机)
说时候,这块笔者没看懂,有点太过于深入的感觉,即使看懂了估计后来也会忘,直接放弃,有兴趣的同学可以看看官方的解释,十分详细:点击这里跳转官方答案
PS:想查看往期文章和题目可以点击下面的链接:
这里是按照日期分类的👇
经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇