LeetCode - 解题笔记 - 65 - Valid Number

Valid Number

Solution 1

整理一下一个有效数字可以包含五个部分:符号位、整数部分、小数点、小数部分、指数部分。其中除了符号位无条件非必须外,其他的部分存在一些制约条件:

  1. 小数点不能单独存在,只能和整数部分或者小数部分存在(分成两个状态,有整数小数点和无整数小数点)
  2. 指数部分不能单独存在,必须和前半有效部分存在,且指数的有效格式为指数字母加有效整数部分(指数符号、指数整数符号、指数整数部分)

这样的话,整个识别过程就变成了一个状态机(状态编号,当前状态(转移因素),可转移状态),加粗为有效终止态:

  1. 初始状态:符号位(符号)、整数部分(数字)、无整数小数点(小数点)
  2. 符号位:整数部分(数字)、无整数小数点(小数点)
  3. 整数部分整数部分(数字)、有整数小数点(小数点)、指数符号(e或者E)
  4. 无整数小数点:小数部分(数字)
  5. 有整数小数点:指数符号(e或者E)、小数部分(数字)
  6. 小数部分小数部分(数字)、指数符号(e或者E)
  7. 指数符号:指数整数符号(符号)、指数整数(数字)
  8. 指数整数符号:指数整数(数字)
  9. 指数整数指数整数(数字)

按照上述状态转移记录进行模拟,即可在线性时间内,常数空间复杂度下完成判定,只要最终状态在其中一个有效终止态,当前输入就是有效数字。

因为我一直没有写过算法的状态机,而正则表达式太容易出错,这里我参考了官方题解的状态机写法。

  • 时间复杂度: O ( N ) O(N) O(N),其中 N N N为输入的字符个数
  • 空间复杂度: O ( 1 ) O(1) O(1),仅维护常数个状态变量
class Solution {
public:
    bool isNumber(string s) {
        int len = s.size();
        State state= STATE_INITIAL;

        for (auto c: s) {
            Input input = getInput(c);
            if (input == INPUT_OTHER) {
                return false;
            }
            else if (F[state].find(input) == F[state].end()) {
                return false;
            } 
            else {
                state = F[state][input];
            }
        }
        return state == STATE_INTEGER || state == STATE_POINT || state == STATE_DECIMAL || state == STATE_EXP_INTEGER;
    }
    
    
private:
    enum State {
        STATE_INITIAL,
        STATE_SIGN,
        STATE_INTEGER,
        STATE_POINT_WITHOUT_INTEGER,
        STATE_POINT,
        STATE_DECIMAL,
        STATE_EXP,
        STATE_EXP_SIGN,
        STATE_EXP_INTEGER
    };

    enum Input {
        INPUT_SIGN,
        INPUT_NUMBER,
        INPUT_POINT,
        INPUT_E,
        INPUT_OTHER,
    };
    
    unordered_map<State, unordered_map<Input, State>> F{
        {
            STATE_INITIAL,
            {
                {INPUT_SIGN, STATE_SIGN},
                {INPUT_NUMBER, STATE_INTEGER},
                {INPUT_POINT, STATE_POINT_WITHOUT_INTEGER}
            }
        },
        {
            STATE_SIGN,
            {
                {INPUT_NUMBER, STATE_INTEGER},
                {INPUT_POINT, STATE_POINT_WITHOUT_INTEGER}
            }
        },
        {
            STATE_INTEGER,
            {
                {INPUT_NUMBER, STATE_INTEGER},
                {INPUT_POINT, STATE_POINT},
                {INPUT_E, STATE_EXP}
            }
        },
        {
            STATE_POINT_WITHOUT_INTEGER,
            {
                {INPUT_NUMBER, STATE_DECIMAL}
            }
        },
        {
            STATE_POINT,
            {
                {INPUT_E, STATE_EXP},
                {INPUT_NUMBER, STATE_DECIMAL}
            }
        },
        {
            STATE_DECIMAL,
            {
                {INPUT_NUMBER, STATE_DECIMAL},
                {INPUT_E, STATE_EXP},
            }
        },
        {
            STATE_EXP,
            {
                {INPUT_SIGN, STATE_EXP_SIGN},
                {INPUT_NUMBER, STATE_EXP_INTEGER},
            }
        },
        {
            STATE_EXP_SIGN,
            {
                {INPUT_NUMBER, STATE_EXP_INTEGER},
            }
        },
        {
            STATE_EXP_INTEGER,
            {
                {INPUT_NUMBER, STATE_EXP_INTEGER},
            }
        }
    };

    Input getInput(char c) {
        if (c == '+' || c == '-') {
            return INPUT_SIGN;
        } 
        else if (c >= '0' && c <= '9') {
            return INPUT_NUMBER;
        }
        else if (c == '.') {
            return INPUT_POINT;
        }
        else if (c == 'e' || c == 'E') {
            return INPUT_E;
        }
        else {
            return INPUT_OTHER;
        }
    }
};

Solution 2

Solution 1的Python实现

from enum import Enum

class Solution:
    State = Enum("State", [
        "STATE_INITIAL",
        "STATE_SIGN",
        "STATE_INTEGER",
        "STATE_POINT_WITHOUT_INTEGER",
        "STATE_POINT",
        "STATE_DECIMAL",
        "STATE_EXP",
        "STATE_EXP_SIGN",
        "STATE_EXP_INTEGER",
    ])
    
    Inputs = Enum("Inputs", [
        "INPUT_SIGN",
        "INPUT_NUMBER",
        "INPUT_POINT",
        "INPUT_E",
        "INPUT_OTHER",
    ])
        
    F = {
        State.STATE_INITIAL: {
            Inputs.INPUT_SIGN: State.STATE_SIGN,
            Inputs.INPUT_NUMBER: State.STATE_INTEGER,
            Inputs.INPUT_POINT: State.STATE_POINT_WITHOUT_INTEGER
        },
        State.STATE_SIGN: {
            Inputs.INPUT_NUMBER: State.STATE_INTEGER,
            Inputs.INPUT_POINT: State.STATE_POINT_WITHOUT_INTEGER
        },
        State.STATE_INTEGER: {
            Inputs.INPUT_NUMBER: State.STATE_INTEGER,
            Inputs.INPUT_POINT: State.STATE_POINT,
            Inputs.INPUT_E: State.STATE_EXP
        },
        State.STATE_POINT_WITHOUT_INTEGER: {
            Inputs.INPUT_NUMBER: State.STATE_DECIMAL
        },
        State.STATE_POINT: {
            Inputs.INPUT_E: State.STATE_EXP,
            Inputs.INPUT_NUMBER: State.STATE_DECIMAL
        },
        State.STATE_DECIMAL: {
            Inputs.INPUT_NUMBER: State.STATE_DECIMAL,
            Inputs.INPUT_E: State.STATE_EXP
        },
        State.STATE_EXP: {
            Inputs.INPUT_SIGN: State.STATE_EXP_SIGN,
            Inputs.INPUT_NUMBER: State.STATE_EXP_INTEGER
        },
        State.STATE_EXP_SIGN: {
            Inputs.INPUT_NUMBER: State.STATE_EXP_INTEGER
        },
        State.STATE_EXP_INTEGER: {
            Inputs.INPUT_NUMBER: State.STATE_EXP_INTEGER
        },
    }
    
    @classmethod
    def getInput(cls, c: str) -> Inputs:
        if c == '+' or c == '-': 
            return Solution.Inputs.INPUT_SIGN
        elif c.isdigit(): 
            return Solution.Inputs.INPUT_NUMBER
        elif c == '.': 
            return Solution.Inputs.INPUT_POINT
        elif c.lower() == 'e': 
            return Solution.Inputs.INPUT_E
        else: 
            return Solution.Inputs.INPUT_OTHER

    def isNumber(self, s: str) -> bool:
        state = Solution.State.STATE_INITIAL
        
        for c in s:
            print(state)
            inp = Solution.getInput(c)
            if inp == Solution.Inputs.INPUT_OTHER: return False
            elif inp not in Solution.F[state]: return False
            else: state = Solution.F[state][inp]
                
        return state in [Solution.State.STATE_INTEGER, Solution.State.STATE_POINT, Solution.State.STATE_DECIMAL, Solution.State.STATE_EXP_INTEGER]
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值