题目
标题和出处
标题:有效数字
出处:65. 有效数字
难度
8 级
题目描述
要求
有效数字(按顺序)可以分成以下几个部分:
- 一个小数或者整数
- (可选)一个 ‘E’ \texttt{`E'} ‘E’ 或 ‘e’ \texttt{`e'} ‘e’,后面跟着一个整数
小数(按顺序)可以分成以下几个部分:
- (可选)一个符号字符( ‘+’ \texttt{`+'} ‘+’ 或 ‘-’ \texttt{`-'} ‘-’)
- 下述格式之一:
- 至少一位数字,后面跟着一个点 ‘.’ \texttt{`.'} ‘.’
- 至少一位数字,后面跟着一个点 ‘.’ \texttt{`.'} ‘.’,后面再跟着至少一位数字
- 一个点 ‘.’ \texttt{`.'} ‘.’,后面跟着至少一位数字
整数(按顺序)可以分成以下几个部分:
- (可选)一个符号字符( ‘+’ \texttt{`+'} ‘+’ 或 ‘-’ \texttt{`-'} ‘-’)
- 至少一位数字
部分有效数字列举如下:
- ["2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"] \texttt{["2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"]} ["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"] \texttt{["abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]} ["abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]
给你一个字符串 s \texttt{s} s,如果 s \texttt{s} s 是一个有效数字,请返回 true \texttt{true} true。
示例
示例 1:
输入:
s
=
"0"
\texttt{s = "0"}
s = "0"
输出:
true
\texttt{true}
true
示例 2:
输入:
s
=
"e"
\texttt{s = "e"}
s = "e"
输出:
false
\texttt{false}
false
示例 3:
输入:
s
=
"."
\texttt{s = "."}
s = "."
输出:
false
\texttt{false}
false
示例 4:
输入:
s
=
".1"
\texttt{s = ".1"}
s = ".1"
输出:
true
\texttt{true}
true
数据范围
- 1 ≤ s.length ≤ 20 \texttt{1} \le \texttt{s.length} \le \texttt{20} 1≤s.length≤20
- s \texttt{s} s 仅含英语字母(大写和小写),数字( 0-9 \texttt{0-9} 0-9),加号 ‘+’ \texttt{`+'} ‘+’,减号 ‘-’ \texttt{`-'} ‘-’,或者点 ‘.’ \texttt{`.'} ‘.’
解法
思路和算法
这道题的解法有多种,包括正则表达式和有限状态自动机。此处提供的解法只需要遍历字符串即可,不使用正则表达式和有限状态自动机。
题目定义的小数和整数包含一个可选的符号字符,为了方便处理,将可选的符号字符分离,则小数只包含一位至多位数字和一个点,其中点可以位于任何位置,整数只包含一位至多位数字。
根据有效数字中是否有字母 ‘E’ \text{`E'} ‘E’ 或 ‘e’ \text{`e'} ‘e’,可以分成两种情况。
- 有效数字中没有字母,可以分成以下
2
2
2 个部分:
- (可选)一个符号字符( ‘+’ \text{`+'} ‘+’ 或 ‘–’ \text{`--'} ‘–’);
- 一个小数或整数,包含一位至多位数字,最多包含一个点,点可以位于任何位置。
- 有效数字中有字母,可以分成以下
5
5
5 个部分:
- (可选)一个符号字符( ‘+’ \text{`+'} ‘+’ 或 ‘–’ \text{`--'} ‘–’);
- 一个小数或整数,包含一位至多位数字,最多包含一个点,点可以位于任何位置;
- 一个字母 ‘E’ \text{`E'} ‘E’ 或 ‘e’ \text{`e'} ‘e’;
- (可选)一个符号字符( ‘+’ \text{`+'} ‘+’ 或 ‘–’ \text{`--'} ‘–’);
- 一个整数,包含一位至多位数字。
有字母和没有字母相比,多出了 3 3 3 个部分。前 2 2 2 个部分的处理逻辑相同,如果遇到字母,则继续处理后 3 3 3 个部分。
对于可选的第 1 1 1 部分,判断字符串 s s s 的第一个字符(即下标 0 0 0 的字符)是否为符号字符,如果是符号字符则跳过该字符。
对于第 2 2 2 部分,需要依次遍历每个字符,直到遍历到达字符串末尾或者遇到字母。对于遍历的每个字符,需要判断以下方面:
- 每个字符必须是数字或者点,如果遇到符号字符则返回 false \text{false} false;
- 最多只能有一个字符是点,如果遇到两个字符是点则返回 false \text{false} false;
- 点的前面和后面的数字个数不能都是 0 0 0,对于整数的情况,将数字个数记为点的前面的数字个数,遍历结束之后,如果点的前面和后面的数字个数都是 0 0 0 则返回 false \text{false} false。
在上述方面都满足的情况下,遍历结束第 2 2 2 部分之后,如果到达字符串末尾,则是没有字母的有效数字,返回 true \text{true} true。
如果尚未到达字符串末尾,则当前字符一定是字母,如果当前字符是 ‘E’ \text{`E'} ‘E’ 或 ‘e’ \text{`e'} ‘e’,则该字符为第 3 3 3 部分,否则当前字符不是有效数字的合法字符,返回 false \text{false} false。
对于可选的第 4 4 4 部分,判断当前字符是否为符号字符,如果是符号字符则跳过该字符。
对于第 5 5 5 部分,需要依次遍历每个字符,直到遍历到达字符串末尾。必须至少有一个字符且每个字符必须都是数字,如果没有字符或者遇到非数字的字符则返回 false \text{false} false。
到达字符串末尾时,如果每个部分的要求都满足,则是有字母的有效数字,返回 true \text{true} true。
代码
class Solution {
public boolean isNumber(String s) {
int length = s.length();
int index = 0;
if (s.charAt(index) == '+' || s.charAt(index) == '-') {
index++;
}
if (index == length) {
return false;
}
int beforePoint = 0, afterPoint = 0;
boolean point = false;
while (index < length && !Character.isLetter(s.charAt(index))) {
char c = s.charAt(index);
if (c == '.') {
if (!point) {
point = true;
} else {
return false;
}
} else if (Character.isDigit(c)) {
if (!point) {
beforePoint++;
} else {
afterPoint++;
}
} else {
return false;
}
index++;
}
if (beforePoint == 0 && afterPoint == 0) {
return false;
}
if (index == length) {
return true;
}
char letter = s.charAt(index);
if (letter != 'E' && letter != 'e') {
return false;
}
index++;
if (index < length && (s.charAt(index) == '+' || s.charAt(index) == '-')) {
index++;
}
if (index == length) {
return false;
}
while (index < length) {
if (!Character.isDigit(s.charAt(index))) {
return false;
}
index++;
}
return true;
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。需要遍历字符串 s s s 一次,对于每个字符的判断时间都是 O ( 1 ) O(1) O(1)。
-
空间复杂度: O ( 1 ) O(1) O(1)。