超简单的自动机

本文通过分析力扣第8题——字符串转换整数(atoi),介绍了如何使用自动机方法来优雅地解决此类问题。自动机的关键在于状态转移关系的建立,文章中定义了四种状态:start、signed、inNum、end,以及四种事件:空字符、正负号、数字和其他。通过状态转移矩阵,实现了从输入字符串到有效整数的转换。最终,通过实现自动机类简化了解题代码,使得主方法更加简洁高效。
摘要由CSDN通过智能技术生成

  本篇博客由力扣第8题引出,这类题目倒是不难,但在不了解自动机之前写出的代码非常臃肿,暴力解需要考虑大量的细节,需要大量的if-else,用了自动机之后才知道什么叫优雅的代码。

题目介绍:

8. 字符串转换整数 (atoi)
  请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

  • 读入字符串并丢弃无用的前导空格
  • 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
  • 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  • 将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
  • 如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
  • 返回整数作为最终结果。

注意:

  • 本题中的空白字符只包括空格字符 ’ ’ 。
  • 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
  • 0 <= s.length <= 200
  • s 由英文字母(大写和小写)、数字(0-9)、’ ‘、’+’、’-’ 和 ‘.’ 组成

示例 :

输入:s = "42"
输出:42

输入:s = "   -42"
输出:-42

输入:s = "4193 word 98"
输出:4193

输入:s = "words and 987"
输出:0

解题思路

  自动机的关键在于找准状态转移关系,即找出在每种状态下遇到各种事件之后的下一个状态。
  经分析,该题中可以定义四种状态:start、signed、inNum、end;可以定义四种事件:空字符、‘+‘/’-‘、数字、其它;则状态转移关系如下:

当前状态 / 事件空字符‘+‘/’-‘数字其它
startstartsignedinNumend
statedendendinNumend
inNumendendinNumend
endendendendend

将上述思路写成代码,则我们的自动机类为:

class AutoMachine{
    String state;//状态
    int sign;//符号
    long value;//数值
    HashMap<String,String[]>map;//存储状态转移关系
    public AutoMachine(){
        map=new HashMap<>();
        //        ''     +/-    num   else
        //start   start  signed inNum end
        //signed  end    end    inNum end
        //inNum   end    end    inNum end
        //end     end    end    end   end
        map.put("start",new String[]{"start","signed","inNum","end"});
        map.put("signed",new String[]{"end","end","inNum","end"});
        map.put("inNum",new String[]{"end","end","inNum","end"});
        map.put("end",new String[]{"end","end","end","end"});
        state="start";
        sign=1;
        value=0;
    }
    
    public void get(char c){
    	//根据所处状态和给定的字符从map中获取下一状态
        state=map.get(state)[getcol(c)];
        if(state.equals("signed")){
            sign=c=='+'?1:-1;
        }else if(state.equals("inNum")){
            value=value*10+(c-'0');
            //防止溢出
            value=sign==1?Math.min(value,Integer.MAX_VALUE):Math.min(value,-(long)Integer.MIN_VALUE);
        }
    }
    private int getcol(char c){
    	//事件3
        if(Character.isDigit(c)){
            return 2;
        }
        switch (c){
            case ' ': //事件1               
                return 0;
            case '+':
            case '-': //事件2
                return 1;
            default: //事件4
                return 3;
        }
    }
}

有了这个自动机,我们的主方法就会变得非常简洁。

public int myAtoi(String str) {  
    int len=str.length();      
    AutoMachine am=new AutoMachine();
    for(int i=0;i<len;i++){
        am.get(str.charAt(i));
    }
    return (int)am.value*am.sign;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值