一、题目
有效数字(按顺序)可以分成以下几个部分:
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. 字符 e1. 指数部分的符号位1. 指数部分的整数部分
三、代码
1)分段处理
class Solution {public boolean isNumber(String s) {char[] cs = s.toCharArray();int eLoc = findELocation(cs); // 找到e所在的下标,如果没有e,eLoc的值就为cs.lengthreturn 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) { // 没有ereturn 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);elsereturn 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');}}
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)
