确定有限状态自动机

确定优先状态自动机(Deterministic Finite Automation, DFA)是一种计算模型。它包含一系列状态,这些状态中:

  • 有一个特殊的状态,被称作初始状态
  • 还有一系列状态被称为接受状态,它们组成了一个特殊的集合。其中,一个状态可能既是初始状态,也是接受状态

起初,这个自动机处于初始状态。随后,它顺序地读取字符串中的每一个字符,并根据当前状态和读入的字符,按照某个事先约定好的转移规则,从当前状态转移到下一个状态;当状态转移完成后,它就读取下一个字符。当字符串全部读取完毕后,如果自动机处于某个接受状态,则判定该字符串被接受;否则,判定该字符串被拒绝

确定优先状态自动机-01.jpg

如果输入的过程中某一步转移失败了,即不存在对应的转移规则,此时计算将提前中止。在这种情况下我们也判定该字符串被拒绝

确定有限状态自动机总是能够回答某种形式的对于给定的输入字符串S,判断其是否满足条件P的问题。

确定有限状态自动机驱动的编程,可以被看做一种暴力枚举方法的延伸:它穷尽了在任何一种情况下,对应任何的输入,需要做的事情。

自动机在计算机科学领域有着广泛的应用。在算法领域,它与大名鼎鼎的字符串查找算法KMP算法有着密切的关联;在工程领域,它是实现正则表达式的基础。

剑指 Offer 20. 表示数值的字符串为例:

class Solution {
    public boolean isNumber(String s) {
        Map<State, Map<CharType, State>> transfer = new HashMap<>();
        transfer.put(State.STATE_INITIAL, 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_INT_SIGN, new HashMap<CharType, State>() {{
                    put(CharType.CHAR_NUMBER, State.STATE_INTEGER);
                    put(CharType.CHAR_POINT, State.STATE_POINT_WITHOUT_INT);
                }}
        );
        transfer.put(State.STATE_INTEGER, 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_POINT, new HashMap<CharType, State>() {{
                    put(CharType.CHAR_NUMBER, State.STATE_FRACTION);
                    put(CharType.CHAR_EXP, State.STATE_EXP);
                    put(CharType.CHAR_SPACE, State.STATE_END);
                }}
        );
        transfer.put(State.STATE_POINT_WITHOUT_INT, new HashMap<CharType, State>() {{
                    put(CharType.CHAR_NUMBER, State.STATE_FRACTION);
                }}
        );
        transfer.put(State.STATE_FRACTION, new HashMap<CharType, State>() {{
                    put(CharType.CHAR_NUMBER, State.STATE_FRACTION);
                    put(CharType.CHAR_EXP, State.STATE_EXP);
                    put(CharType.CHAR_SPACE, State.STATE_END);
                }}
        );
        transfer.put(State.STATE_EXP, new HashMap<CharType, State>() {{
                    put(CharType.CHAR_NUMBER, State.STATE_EXP_NUMBER);
                    put(CharType.CHAR_SIGN, State.STATE_EXP_SIGN);
                }}
        );
        transfer.put(State.STATE_EXP_SIGN, new HashMap<CharType, State>() {{
                    put(CharType.CHAR_NUMBER, State.STATE_EXP_NUMBER);
                }}
        );
        transfer.put(State.STATE_EXP_NUMBER, new HashMap<CharType, State>() {{
                    put(CharType.CHAR_NUMBER, State.STATE_EXP_NUMBER);
                    put(CharType.CHAR_SPACE, State.STATE_END);
                }}
        );
        transfer.put(State.STATE_END, new HashMap<CharType, State>() {{
                    put(CharType.CHAR_SPACE, State.STATE_END);
                }}
        );

        int len = s.length();
        State state = State.STATE_INITIAL;

        for (int i = 0; i < len; i++) {
            CharType type = toCharType(s.charAt(i));
            if (!transfer.get(state).containsKey(type)) return false;
            else state = transfer.get(state).get(type);
        }

        return state == State.STATE_INTEGER || state == State.STATE_POINT || state == State.STATE_END || state == State.STATE_FRACTION || state == State.STATE_EXP_NUMBER;
    }

    public CharType toCharType(char c) {
        if (c >= '0' && c <= '9') return CharType.CHAR_NUMBER;
        if (c == 'e' || c == 'E') return CharType.CHAR_EXP;
        if (c == '.') return CharType.CHAR_POINT;
        if (c == '+' || c == '-') return CharType.CHAR_SIGN;
        if (c == ' ') return CharType.CHAR_SPACE;
        return CharType.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
    }

    enum CharType {
        CHAR_NUMBER,
        CHAR_EXP,
        CHAR_POINT,
        CHAR_SIGN,
        CHAR_SPACE,
        CHAR_ILLEGAL
    }
}

状态一定要定义好,小数后的整数和小数的前的整数是不一致的,需要使用不同的状态STATE_INTEGERSTATE_FRACTION

参考文献:

  1. 表示数值的字符串
  2. 浅谈DFA确定有限状态自动机
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容