Valid Number
题目
题目链接:https://leetcode.com/problems/valid-number/
Validate if a given string can be interpreted as a decimal number.
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
Note:
It is intended for the problem statement to be ambiguous. You should gather all requirements up front before implementing one. However, here is a list of characters that can be in a valid decimal number:
- Numbers 0-9
- Exponent - “e”
- Positive/negative sign - “+”/"-"
- Decimal point - “.”
Of course, the context of these characters also matters in the input.
分析
这道题其实就是给你一个字符串,让你判断这个字符串是不是一个实数。
那么,怎么表示的数才是一个实数呢?
首先去掉前后的空白字符(和
\t
)。
剩下的子串中最前面可以有+
或者是-
号。然后是整数部分,小数点和小数部分。需要注意的是:正负号可有可无,只能有一个;整数,小数点和小数部分可以是下面任意一种形式,a.b
,a.
,a
和.b
。不能是.
(ab
其实就是a
,b
其实就是a
)。
上面那部分可以作为一个完整的实数表示了,也可以还有指数部分。指数部分需要与上面那部分一起出现(在它们后面),不能单独出现。
指数部分以e
开头,接正负号,整数。需要注意的是在有指数部分的情况下:e
必须有;正负号可有可无,只能有一个;整数必须有,可以是0,不能包含小数点。
这道题可以有下面三种解法:
- 使用Java中自带的
Double.valueOf(String s)
方法
这算是一种偷懒的方法。直接利用已有的方法。
当其尝试转换一个不是数的字符串时会抛出异常,我们可以捕获这个异常并且return false
。否则return true
。
但是需要注意的是,Double.valueOf
方法在判断时,如果给出的字符串以D
或者d
结尾(表示double
类型),或者是以f
或者F
结尾(表示float
类型),或者指数以E
表示(题目中是以e
表示)时,也能正确解析。因此我们需要先判断上面的几种例外情况,然后再利用Double.valueOf
方法。
但是这种方法时间复杂度并不低。 - 使用正则表达式
自己手写一个正则表达式,然后使用String.matches(String pattern)
方法。
最后的正则表达式如下:\\s[+-]?(?:[0-9]+(?:\\.[0-9]*)?|\\.[0-9]+)(?:e[+-]?[0-9]+)?\\s
。需要注意的是,\s
表示空白字符,再java中必须使用\\
表示\
,否则会将\s
当做是转义字符。\.
也同理,需要用\\.
表示。
这种方法时间复杂度很高,比第一种慢很多。 - 普通方法(遍历判断)
从左到右遍历这个字符串。然后逐步利用上面的要求进行判断。下面的代码可以清晰地看到这个判断过程,此处不进行叙述。
代码如下
方法一
class Solution {
public boolean isNumber(String s) {
if (s.contains("f") || s.contains("F") || s.contains("D") || s.contains("d") || s.contains("E")) {
return false;
}
try {
Double.valueOf(s);
return true;
} catch (Exception e) {
return false;
}
}
}
方法二
class Solution {
public boolean isNumber(String s) {
s = s.trim();
// 这里先去除了s前后地空白字符,因此正则表达式前后不用加上 \\s 。
// ?: 表示非捕获匹配。不影响匹配结果。为了不影响阅读,可以将其去掉
String pattern = "[+-]?(?:[0-9]+(?:\\.[0-9]*)?|\\.[0-9]+)(?:e[+-]?[0-9]+)?";
return s.matches(pattern);
}
}
方法三
class Solution {
public boolean isNumber(String s) {
char[] values = s.toCharArray();
int index = 0;
boolean integer = false; // 整数部分
boolean fraction = false; // 小数部分
boolean blank = false; // 中间是否有空白部分
boolean exponent = false; // 指数
// 跳过空白字符
while (index < values.length && (values[index] == ' ' || values[index] == '\t')) {
index++;
}
if (index >= values.length) {
return false;
}
// 正负号
if (index < values.length && (values[index] == '+' || values[index] == '-')) {
index++;
}
if (index >= values.length) {
return false;
}
// 整数部分
while (index < values.length && values[index] >= '0' && values[index] <= '9') {
integer = true; // 有整数部分
index++;
}
// 小数点
if (index < values.length && values[index] == '.') {
index++;
}
// 小数部分
while (index < values.length && values[index] >= '0' && values[index] <= '9') {
fraction = true;
index++;
}
// 没有整数也没有小数(小数点有没有都无所谓)
if (!integer && !fraction) {
return false;
}
// 结尾部分的空白字符
while (index < values.length && (values[index] == ' ' || values[index] == '\t')) {
blank = true;
index++;
}
// 到达末尾
if (index == values.length) {
return true;
} else if (blank) {
return false;
}
// 指数e
if (values[index] == 'e' && index + 1 < values.length) {
index++;
} else {
return false;
}
// 指数部分的正负号
if (values[index] == '+' || values[index] == '-') {
index++;
}
// 指数
while (index < values.length && values[index] >= '0' && values[index] <= '9') {
exponent = true;
index++;
}
// 没有指数
if (!exponent) {
return false;
}
// 结尾部分的空白字符
while (index < values.length && (values[index] == ' ' || values[index] == '\t')) {
index++;
}
if (index >= values.length) {
return true;
} else {
return false;
}
}
}