这是《剑指Offer》中一道比较有意思的题,题目可以查看:
https://leetcode-cn.com/problems/biao-shi-shu-zhi-de-zi-fu-chuan-lcof/
需要判断给定的字符串是否是一个数值。
采用的解题方法是自动机:
自动机的介绍:
确定有限状态自动机(以下简称「自动机」)是一类计算模型。它包含一系列状态,这些状态中:
有一个特殊的状态,被称作「初始状态」。
还有一系列状态被称为「接受状态」,它们组成了一个特殊的集合。其中,一个状态可能既是「初始状态」,也是「接受状态」。
起初,这个自动机处于「初始状态」。随后,它顺序地读取字符串中的每一个字符,并根据当前状态和读入的字符,按照某个事先约定好的「转移规则」,从当前状态转移到下一个状态;当状态转移完成后,它就读取下一个字符。当字符串全部读取完毕后,如果自动机处于某个「接受状态」,则判定该字符串「被接受」;否则,判定该字符串「被拒绝」。
注意:如果输入的过程中某一步转移失败了,即不存在对应的「转移规则」,此时计算将提前中止。在这种情况下我们也判定该字符串「被拒绝」。
一个自动机,总能够回答某种形式的「对于给定的输入字符串 S,判断其是否满足条件 P」的问题。在本题中,条件 P 即为「构成合法的表示数值的字符串」。
自动机驱动的编程,可以被看做一种暴力枚举方法的延伸:它穷尽了在任何一种情况下,对应任何的输入,需要做的事情。
则首先,我们定义字符具有的类型以及所有的状态类型:
enum CharType {
CHAR_NUMBER, // 数字
CHAR_EXP, // e或E
CHAR_POINT, // 小数点
CHAR_SIGN, // + 或 -
CHAR_SPACE,
CHAR_ILLEGAL,
}
enum State {
STATE_INITIAL, // 初始状态
STATE_INT_SIGN, // 符号
STATE_INTEGER, // 整数
STATE_POINT, // 小数点
STATE_POINT_WITHOUT_INT,
STATE_FRACTION,
STATE_EXP,
STATE_EXP_SIGN,
STATE_EXP_NUMBER,
STATE_END,
}
接着构造“转移规则”,也可以理解为每个状态对应极其对应的可接受状态集合
// transfer用来记录每个状态State 对应的 可接受状态集合,其中可接受状态Map<CharType, State>中的State是对应CharType
Map<State, Map<CharType, State>> transfer = new HashMap<State, Map<CharType, State>>();
// STATE_INITIAL状态对应的可接受状态是initialMap中的4种状态
// initialMap中的State表示的是 CharType在上个State的条件下出现所代表的状态
Map<CharType, State> initialMap = new HashMap<CharType, State>() {
{
put(CharType.CHAR_SPACE, State.STATE_INITIAL);
put(CharType.CHAR_NUMBER, State.STATE_INTEGER);
put(CharType.CHAR_POINT, State.STATE_POINT_WITHOUT_INT);
put(CharType.CHAR_SIGN, State.STATE_INT_SIGN);
}};
transfer.put(State.STATE_INITIAL, initialMap);
// STATE_INT_SIGN状态对应的可接受状态是intSignMap中的2种状态
Map<CharType, State> intSignMap = new HashMap<CharType, State>() {
{
put(CharType.CHAR_NUMBER, State.STATE_INTEGER);
put(CharType.CHAR_POINT, State.STATE_POINT_WITHOUT_INT);
}};
transfer.put(State.STATE_INT_SIGN, intSignMap);
// STATE_INTEGER状态对应的可接受状态是integerMap中的4种状态
Map<CharType, State> integerMap = new HashMap<CharType, State>() {
{
put(CharType.CHAR_NUMBER, State.STATE_INTEGER);
put(CharType.CHAR_EXP, State.STATE_EXP);
put(CharType.CHAR_POINT, State.STATE_POINT);
put(CharType.CHAR_SPACE, State.STATE_END);
}};
transfer.put(State.STATE_INTEGER, integerMap);
// STATE_POINT状态对应的可接受状态是pointMap中的3种状态
Map<CharType, State> pointMap = new HashMap<CharType, State>() {