难度:中等
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
数值(按顺序)可以分成以下几个部分:
- 若干空格
- 一个 小数 或者 整数
- (可选) 一个 'e' 或 'E' ,后面跟着一个 整数
- 若干空格
小数(按顺序)可以分成以下几个部分:
(可选)一个符号字符('+' 或 '-')
下述格式之一:
- 至少一位数字,后面跟着一个点 '.'
- 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
- 一个点 '.' ,后面跟着至少一位数字
整数(按顺序)可以分成以下几个部分:
- (可选)一个符号字符('+' 或 '-')
- 至少一位数字
部分数值列举如下:
["+100", "5e2", "-123", "3.1416", "-1E-16", "0123"]
部分非数值列举如下:
["12e", "1a3.14", "1.2.3", "+-5", "12e+5.4"]
本题属于典型的字符串校验问题。
字符串校验问题不考察典型的数据结构或算法,而是考察考虑问题的周到程度。很多人并不喜欢这类问题,因为过程往往非常繁琐。
实际上,这种问题可以看做业务逻辑的一种抽象。在业务开发中,也经常需要碰见类似的情况,例如判断一个字符串是不是符合标准,因此这类问题还是有一定实际意义的。
【解】
字符串校验问题的核心在于归纳,要么归纳出所有不合条件的,剩下的都符合条件;要么直接归纳出所有符合条件的情况返回,这里采用方法一,归纳出所有不合条件的,剩下的就一定符合条件
首先,先对字符串做一些处理:
1) 去掉字符串左右两端的干扰空格
2) 如果有正负号,去掉正负号(把后面的内容当做一个无符号数看待)
3) 如果在上面两步结束以后,字符串长度为1,那这个字符一定要在0~9之间,否则不合条件
做完上面几步后,就可以根据归纳,分别对每一种情况做处理:
1. '.'字符
1) 字符串中只能有一个点字符
2) 不能在E的后面;如果在E的前一位,那么它的前面必须有数字('.'不能在第一位)
2. 'e' 或 'E'
1) 字符串中只能有一个E或e字符
2) 不能在最前面或最后面
3. '+' 或 '-'
1) 在去掉开头的正负号后,只能出现在E后一位,而且不能是整个字符串的最后一位
4. '0' ~ '9'
符合条件,continue
5. 其它字符,不符合条件,直接返回false
在经过上面的归纳后,剩下的一定是符合条件的字符串
代码如下:
class Solution {
public boolean isNumber(String s) {
// 去空格
s = s.trim();
if (s.equals("")) return false;
// 有符号就去符号,如果去掉以后后面没有元素了,说明不符合条件,返回false
if (s.charAt(0) == '+' || s.charAt(0) == '-') s = s.substring(1);
if (s.equals("")) return false;
// 前置工作完成,开始扫描字符串
int length = s.length();
if (length == 1 && (s.charAt(0) > '9' || s.charAt(0) < '0')) return false;
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
// 1) 如果是'.' 1.出现多个点,false; 2.在e后,false
if (c == '.') {
if (map.containsKey('.')) return false;
if (map.containsKey('e')) return false;
map.put('.', i);
}
// 2) 如果是'e'或'E' 1.出现多个e,false; 2.出现在最前或最后,false; 3.e前面有.且.是第一个元素,false
else if (c == 'e' || c == 'E') {
if (map.containsKey('e')) return false;
if (i == 0 || i == length - 1) return false;
if (map.containsKey('.') && map.get('.') + 1 == i && i == 1) return false;
map.put('e', i);
}
// 3) 如果是'+'或'-' 只能在e后面,而且不能在最后
else if (c == '+' || c == '-') {
if (map.containsKey('e') && map.get('e') + 1 == i && i != length - 1) {
continue;
} else {
return false;
}
}
else if ('0' <= c && c <= '9') {
continue;
}
else {
return false;
}
}
return true;
}
}