LeetCode 65. 有效数字(有限状态机、正则)

65. 有效数字

2021.6.17每日一题

题目描述
有效数字(按顺序)可以分成以下几个部分:

一个 小数 或者 整数
(可选)一个 'e' 或 'E' ,后面跟着一个 整数
小数(按顺序)可以分成以下几个部分:

(可选)一个符号字符('+' 或 '-')
下述格式之一:
至少一位数字,后面跟着一个点 '.'
至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
一个点 '.' ,后面跟着至少一位数字
整数(按顺序)可以分成以下几个部分:

(可选)一个符号字符('+' 或 '-')
至少一位数字
部分有效数字列举如下:

["2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"]
部分无效数字列举如下:

["abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]
给你一个字符串 s ,如果 s 是一个 有效数字 ,请返回 true 。

 

示例 1:

输入:s = "0"
输出:true
示例 2:

输入:s = "e"
输出:false
示例 3:

输入:s = "."
输出:false
示例 4:

输入:s = ".1"
输出:true

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

有限状态机,剑指offer20题写过

class Solution {
    public boolean isNumber(String s) {
        //一种直接if的方法,一种有限状态机吧
        //开始状态,能转移到“整数部分的数字数字,.,+/-”        0
        //左侧有整数的小数点,能转移到小数部分的数字,e,结束   1
        //整数部分的数字,能转移到e,左侧有整数的小数点,结束,整数部分的数字 2
        //+/-,能转移到数字,左侧无整数的小数点 3
        //左侧无整数的小数点,能转移到小数部分的数字,  4
        //小数部分的数字,能转移到小数部分的数字,e,结束   5
        //e,能转移到指数数字,指数符号+/-      6
        //指数符号+/-,能转移到指数数字     7
        //指数数字,能转移到指数数字,结束  8
        Map[] states = {
            new HashMap<>(){{ put('d', 2); put('s', 3); put('.', 4); }},    //0,开始状态
            new HashMap<>(){{ put('d', 5); put('e', 6); }},                 //1,左侧有整数的小数点
            new HashMap<>(){{ put('d', 2); put('e', 6); put('.', 1); }},    //2,整数部分的数字
            new HashMap<>(){{ put('d', 2); put('.', 4); }},                 //3,+/-
            new HashMap<>(){{ put('d', 5); }},                              //4,左侧无整数的小数点    
            new HashMap<>(){{ put('d', 5); put('e', 6); }},                 //5,小数部分的数字
            new HashMap<>(){{ put('d', 8); put('s', 7); }},                 //6,e
            new HashMap<>(){{ put('d', 8); }},                              //7,指数符号+/-
            new HashMap<>(){{ put('d', 8); }}                               //8,指数数字
        };
        //刚开始在状态0
        int p = 0;
        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            char t;
            if(c >= '0' && c <= '9')    t = 'd';
            else if(c == '+' || c == '-') t = 's';
            else if(c == '.')   t = '.';
            else if(c == 'e' || c == 'E') t = 'e';
            else
                t = '?';
            //如果不包含这个状态,直接false
            if(!states[p].containsKey(t))
                return false;
            //状态转移
            p = (int)states[p].get(t);
        }
        return p == 1 || p == 2 || p == 5 || p == 8;
    }
}

学了正则,来试着用正则表达式写一下:

import java.util.regex.Pattern;
class Solution {
    public boolean isNumber(String s) {
        //正负号可出现可不出现
        //然后是数字.,数字.数字或者.数字
        //然后指数部分可有可无
        //指数部分,就是e/E[+-]?\\d+
        Pattern pattern  = Pattern.compile("[+-]?((\\d+\\.\\d*)|(\\.?\\d+))([eE][+-]?\\d+)?");
        return pattern.matcher(s).matches();
    }
}

也可以写成一张表,学习一下:

class Solution {
    public int make(char c) {
        switch(c) {
            case ' ': return 0;
            case '+':
            case '-': return 1;
            case '.': return 3;
            case 'e': return 4;
            default:
                if(c >= 48 && c <= 57) return 2;
        }
        return -1;
    }
    
    public boolean isNumber(String s) {
        int state = 0;
        int finals = 0b101101000;
        int[][] transfer = new int[][]{{ 0, 1, 6, 2,-1},
                                       {-1,-1, 6, 2,-1},
                                       {-1,-1, 3,-1,-1},
                                       { 8,-1, 3,-1, 4},
                                       {-1, 7, 5,-1,-1},
                                       { 8,-1, 5,-1,-1},
                                       { 8,-1, 6, 3, 4},
                                       {-1,-1, 5,-1,-1},
                                       { 8,-1,-1,-1,-1}};
        char[] ss = s.toCharArray();
        for(int i=0; i < ss.length; ++i) {
            int id = make(ss[i]);
            if (id < 0) return false;
            state = transfer[state][id];
            if (state < 0) return false;
        }
        return (finals & (1 << state)) > 0;
    }
}

作者:user8973
链接:https://leetcode-cn.com/problems/valid-number/solution/biao-qu-dong-fa-by-user8973/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

三叶姐的模拟,思路就是根据e/E将字符串分成两部分,然后判断两部分是否为整数或者浮点数

class Solution {
    public boolean isNumber(String s) {
        int n = s.length();
        char[] cs = s.toCharArray();
        int idx = -1;
        for (int i = 0; i < n; i++) {
            if (cs[i] == 'e' || cs[i] == 'E') {
                if (idx == -1) idx = i;
                else return false;
            }
        }
        boolean ans = true;
        if (idx != -1) {
            ans &= check(cs, 0, idx - 1, false);
            ans &= check(cs, idx + 1, n - 1, true);
        } else {
            ans &= check(cs, 0, n - 1, false);
        }
        return ans;
    }
    boolean check(char[] cs, int start, int end, boolean mustInteger) {
        if (start > end) return false;
        if (cs[start] == '+' || cs[start] == '-') start++;
        boolean hasDot = false, hasNum = false;
        for (int i = start; i <= end; i++) {
            if (cs[i] == '.') {
                if (mustInteger || hasDot) return false;
                hasDot = true;
            } else if (cs[i] >= '0' && cs[i] <= '9') {
                hasNum = true;
            } else {
                return false;
            }
        }
        return hasNum;
    }
}

作者:AC_OIer
链接:https://leetcode-cn.com/problems/valid-number/solution/gong-shui-san-xie-zi-fu-chuan-mo-ni-by-a-7cgc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值