65. 有效数字-每日一题

一、题目

  有效数字(按顺序)可以分成以下几个部分:

  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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

佳鑫大大

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值