一、题目
有效数字(按顺序)可以分成以下几个部分:
1. 一个 小数 或者 整数 1. (可选)一个 'e' 或 'E' ,后面跟着一个 整数
小数(按顺序)可以分成以下几个部分:
1. (可选)一个符号字符('+' 或 '-') 1. 下述格式之一: 1. 至少一位数字,后面跟着一个点 '.' 1. 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字 1. 一个点 '.' ,后面跟着至少一位数字
整数(按顺序)可以分成以下几个部分:
1. (可选)一个符号字符('+' 或 '-') 1. 至少一位数字
部分有效数字列举如下:
["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)分段处理
这个思路很简单,就是根据题意分段去验证是否符合题意。
先找到e的下标,整体分为两段进行验证。
前半段:
找到小数点,又分为两段验证
后半段:
直接验证
2)确定有限状态自动机(摘自官方题解)
挖掘出所有状态:
1. 初始状态
1. 符号位
1. 整数部分
1. 左侧有整数的小数点
1. 左侧无整数的小数点(根据前面的第二条额外规则,需要对左侧有无整数的两种小数点做区分)
1. 小数部分
1. 字符 e
1. 指数部分的符号位
1. 指数部分的整数部分
三、代码
1)分段处理
class Solution {
public boolean isNumber(String s) {
char[] cs = s.toCharArray();
int eLoc = findELocation(cs); // 找到e所在的下标,如果没有e,eLoc的值就为cs.length
return checkPre(cs, 0, eLoc) && checkBack(cs, eLoc + 1);
}
private boolean checkBack(char[] cs, int eLoc) {
if (eLoc == cs.length) { // 有e,但后面没有数字的情况
return false;
} else if (eLoc > cs.length) { // 没有e
return true;
}
if (cs[eLoc] == '+' || cs[eLoc] == '-') { // 去掉有符号的情况
eLoc++;
}
return isAllNumber(cs, eLoc, cs.length); // 验证(eLoc, cs.length)部分是否全为数字
}
private boolean checkPre(char[] cs, int s, int eLoc) {
int dotLoc = findDotLocation(cs, s, eLoc);
if (cs[s] == '+' || cs[s] == '-') { // 去掉有符号的情况
s++;
}
if (eLoc - s >= 2) // 2个或更多个字符(包含了.前或后有数字的情况)
return isAllNumberOrNone(cs, s, dotLoc) && isAllNumberOrNone(cs, dotLoc + 1, eLoc);
else
return isSingleNum(cs[s]); // 只有一个字符的情况进行判断
}
private int findDotLocation(char[] cs, int s, int e) {
for (; s < e; s++) {
if (cs[s] == '.') {
break;
}
}
return s;
}
private boolean isAllNumberOrNone(char[] cs, int s, int e) {
while (s < e) {
if (!isSingleNum(cs[s])) {
return false;
}
s++;
}
return true;
}
private boolean isAllNumber(char[] cs, int s, int e) {
if (s == e) {
return false;
}
while (s < e) {
if (!isSingleNum(cs[s])) {
return false;
}
s++;
}
return true;
}
private int findELocation(char[] cs) {
int loc = 0;
for (; loc < cs.length; loc++) {
if (cs[loc] == 'e' || cs[loc] == 'E') {
break;
}
}
return loc;
}
private boolean isSingleNum(char c) {
return (c >= '0' && c <= '9');
}
}
时间复杂度为O(n)
,空间复杂度为O(n)
2)确定有限状态自动机
class Solution {
public boolean isNumber(String s) {
Map<State, Map<Symbol, State>> record = new HashMap();
Map<Symbol, State> initialMap = new HashMap() {{
put(Symbol.NUM, State.BASE_INTEGER);
put(Symbol.SIGN, State.SIGN);
put(Symbol.DOT, State.DOT_LNONE);
}};
record.put(State.INITIAL, initialMap);
Map<Symbol, State> signMap = new HashMap() {{
put(Symbol.NUM, State.BASE_INTEGER);
put(Symbol.DOT, State.DOT_LNONE);
}};
record.put(State.SIGN, signMap);
Map<Symbol, State> baseIntegerMap = new HashMap() {{
put(Symbol.NUM, State.BASE_INTEGER);
put(Symbol.DOT, State.DOT_LEXIST);
put(Symbol.E, State.E);
put(Symbol.END, State.END);
}};
record.put(State.BASE_INTEGER, baseIntegerMap);
Map<Symbol, State> dotLExistMap = new HashMap() {{
put(Symbol.NUM, State.BASE_DECIMAL);
put(Symbol.E, State.E);
put(Symbol.END, State.END);
}};
record.put(State.DOT_LEXIST, dotLExistMap);
Map<Symbol, State> dotLNoneMap = new HashMap() {{
put(Symbol.NUM, State.BASE_DECIMAL);
}};
record.put(State.DOT_LNONE, dotLNoneMap);
Map<Symbol, State> baseDecimalMap = new HashMap() {{
put(Symbol.NUM, State.BASE_DECIMAL);
put(Symbol.E, State.E);
put(Symbol.END, State.END);
}};
record.put(State.BASE_DECIMAL, baseDecimalMap);
Map<Symbol, State> eMap = new HashMap() {{
put(Symbol.SIGN, State.INDEX_SIGN);
put(Symbol.NUM, State.INDEX_NUM);
}};
record.put(State.E, eMap);
Map<Symbol, State> indexSignMap = new HashMap() {{
put(Symbol.NUM, State.INDEX_NUM);
}};
record.put(State.INDEX_SIGN, indexSignMap);
Map<Symbol, State> indexNumMap = new HashMap() {{
put(Symbol.NUM, State.INDEX_NUM);
put(Symbol.END, State.END);
}};
record.put(State.INDEX_NUM, indexNumMap);
// System.out.println(record.toString());
Map<Symbol, State> curruntStateMap = initialMap;
for (char c : s.toCharArray()) {
Symbol curruntSymbol = checkSymbol(c);
if (!curruntStateMap.containsKey(curruntSymbol)) {
return false;
}
curruntStateMap = record.get(curruntStateMap.get(curruntSymbol));
}
return curruntStateMap.containsKey(Symbol.END); // 判断该截至节点是否可以作为end节点
}
private Symbol checkSymbol(char c) {
if (c >= '0' && c <= '9') {
return Symbol.NUM;
} else if (c == 'e' || c == 'E') {
return Symbol.E;
} else if (c == '.') {
return Symbol.DOT;
} else if (c == '+' || c == '-') {
return Symbol.SIGN;
}
return Symbol.OTHER;
}
enum State {
INITIAL,
SIGN,
BASE_INTEGER,
DOT_LEXIST,
DOT_LNONE,
BASE_DECIMAL,
E,
INDEX_SIGN,
INDEX_NUM,
END
}
enum Symbol {
NUM,
E,
DOT,
SIGN,
OTHER,
END
}
}
时间复杂度为O(n)
,空间复杂度为O(1)