有限状态机是什么

399 阅读2分钟

有限状态机

先看一道恶心的面试题:

image.png

最简单的思路:对字符串进行遍历,分别对遇到的字符串进行分情况讨论。例如对于一些简单字符串, 如只有数字和正负号还有不合规字符的”+100, -123sdjhg“,我们可以写下如下代码:

function isNumber(s:string){
   for(let i=0; i<s.length; i++){
      const c = s[i]
      if('+-'.includes(c)){
        if(i>0) return false
      } else if(/[0-9]/.test(c)){
         continue   
      } else {
        return false
      }
   }
   return true
}

然而,在这个题目里,要求判断的数字,我们面临着更多的情况。如:开头可以是空格,可以是”+-”, 还可以是数字、小数点;数字后面可以跟小数点、e、数字;结尾可以是空格、数字、或者小数点。并且对于不同情况下的小数点,后面可以跟的东西又不同,如’.’不可以是一个数字,’3.‘就是一个数字。小数点前的数字和小数点后的数字能够跟的东西都不相同了。想一想这些东西排列组合一下,可以组合出多少种情况,如果用if-elseif-else去写,不知道要写到猴年马月,并且难免会有一些遗漏。

这时候,有限状态机就出来帮助你啦。什么是有限状态机呢?首先看状态,状态在这个题目就是字符串里的每一个字符所处的场景,也就是if-else里的if,也就是现在读到的字符后面可以跟哪些东西。把这个状态写成一个表,通过它,你可以对上述这些情况分别定义状态,每读到一个字符,就根据它的类型去判断它所在的状态,就是判断它后面可以跟那些东西,如果没有状态,那就是判断失败,就可以得出结论了。

直接上代码:

function isNumber(s: string): boolean {
    // 状态 0 空格 1 数字
    // 类型 sign, num, dot, e, 
    const states = [
        {
            num: 1,
            sign: 8,
            dot: 9,
            blank: 0
        }, // 开头的空格
        {
            dot: 3,
            num: 1,
            e: 4,
            blank: 6

        }, // 点前的数字
        {
            e: 4,
            num: 2,
            blank: 6

        }, //点后的数字
        {
            num: 2,
            blank: 6,
            e: 4
        }, // 点
        {
            num: 5,
            sign: 7
        },// e
        {
            num: 5,
            blank: 6
        }, // e后的数字
        {
            blank: 6
        }, //结尾的空格
        {
            num: 5    
        }, // e后面的正负号
        {
            num: 1,
            dot: 9

        }, // 正负号
        {
            num: 2
        }
    ]
    let t = "blank"
    let p = 0
    for(const c of s){
        if(/[0-9]/.test(c)){
            t = 'num'
        } else if (c===' '){
            t = 'blank'
        } else if ('+-'.includes(c)){
            t = 'sign'
        } else if ('eE'.includes(c)){
            t = 'e'
        } else if (c==='.'){
            t = 'dot'
        } else t = 's'
        p = states[p][t]
        console.log(p,c,t)
        if(!p&&p!==0){
            return false
        }
    }
    return [6,1,2,3,5].includes(p)

};

启示:对于一种情况决定另一种情况,并且前后有多种情况依次关联的题目类型,应采用有限状态机,可以减少if-else的使用,保证触达所有场景。