有关有限状态自动机

作者最近在leetcode上遇到了可以用有限状态自动机来解决的题目,在此记录自动状态机思想及其应用。

有限状态自动机(以下简称「自动机」)是一类计算模型。它包含一系列状态,这些状态中:有一种特殊的状态,被称作「初始状态」。还有一系列状态被称为「接受状态」,它们组成了一个特殊的集合。其中,一个状态可能既是「初始状态」,也是「接受状态」。
起初,这个自动机处于「初始状态」。随后,它顺序地读取字符串中的每一个字符,并根据当前状态和读入的字符,按照某个事先约定好的「转移规则」,从当前状态转移到下一个状态;当状态转移完成后,它就读取下一个字符。当字符串全部读取完毕后,如果自动机处于某个「接受状态」,则判定该字符串「被接受」;否则,判定该字符串「被拒绝」。

我们可以将各种状态按照其规定的转移规则写入一个表格中,用map来实现该表格。于是,我们便可以通过访问key(当前状态),找到value(下一个状态)。

题目:

此类关于字符串处理的题目一般都具有复杂的条件判断和流程,手写if-else语句会非常麻烦。所以我们考虑用有限状态自动机,一个字符一个字符的进行处理。

首先,我们根据题目要求画出不同状态之间的关系图:

然后再将此关系图整理列为表格:

 然后我们再通过map对该表格进行储存,其实现代码如下:

string state = "start";    //初始state为“start”
unordered_map<string,vector<string>> table ={
{"start",{"start","signed","in_number","end"}},
{"signed",{"end","end","in_number","end"}},
{"in_number",{"end","end","in_number","end"}},
{"end",{"end","end","end","end"}}
};
//使用unordered_map更高效地查找元素

然后,我们需要设计一个函数来判断当前字符应该对应哪一种状态

int get_col(char c){
        if(isspace(c))
            return 0;
        if(c=='+' || c=='-')
            return 1;
        if(isdigit(c))
            return 2;
        return 3;
    }

可见,这样的判断仅对于单个字符,就避免了繁杂的判断条件。

下一步,我们需要在“in_number”状态下将当前字符计入总数:

    int sign = 1;       //记录正负
    long long ans = 0;  //记录总数

    void get(char c)
    {
        state = table[state][get_col(c)];
        if(state=="in_number")          //在“in_number”状态就需要记录总数
        {
            ans = ans*10+c-'0';
            ans = sign ==1?min(ans,(long long)INT_MAX):min(ans,-(long long)INT_MIN);    //此处计算的是ans的绝对值
        }
        else if(state == "signed")      //判断正负
            sign = c =='+'?1:-1;

    }

我们将上述操作封装在一个名为Automation的类中,此后我们只需要对字符串中的字符进行依次遍历,最后再返回Automation中的ans即可,当然不要忘记考虑正负。

以下是完整代码:

class Automation{
    string state = "start";//初始state为“start”
    unordered_map<string,vector<string>> table ={
        {"start",{"start","signed","in_number","end"}},
        {"signed",{"end","end","in_number","end"}},
        {"in_number",{"end","end","in_number","end"}},
        {"end",{"end","end","end","end"}}
    };
     //使用unordered_map更高效地查找元素
    int get_col(char c){
        if(isspace(c))
            return 0;
        if(c=='+' || c=='-')
            return 1;
        if(isdigit(c))
            return 2;
        return 3;
    }
public:
    int sign = 1;       //记录正负
    long long ans = 0;  //记录总数

    void get(char c)
    {
        state = table[state][get_col(c)];
        if(state=="in_number")          //在“in_number”状态就需要记录总数
        {
            ans = ans*10+c-'0';
            ans = sign ==1?min(ans,(long long)INT_MAX):min(ans,-(long long)INT_MIN);    //此处计算的是ans的绝对值
        }
        else if(state == "signed")      //判断正负
            sign = c =='+'?1:-1;

    }
};
class solution{
public:
    int strToint(string str){
        Automation automation;
        for(auto x:str)
        {
            automation.get(x);
        }
        return automation.sign * automation.ans;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值