冬瓜头学编程第三站——表示数值的字符串

文章介绍了如何判断一个字符串是否表示数值,包括整数和小数。主要思路是通过枚举和有限状态自动机来分析字符串的各个部分,如正负号、小数点、指数等。文章提供了两种方法,一种是暴力枚举,另一种是使用更规范的状态转移枚举策略,后者在处理大规模程序时更为高效。
摘要由CSDN通过智能技术生成

题目描述:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。

数值(按顺序)可以分成以下几个部分:

  1. 若干空格
  2. 一个 小数 或者 整数
  3. (可选)一个 'e' 或 'E' ,后面跟着一个 整数
  4. 若干空格

小数(按顺序)可以分成以下几个部分:

  1. (可选)一个符号字符('+' 或 '-'
  2. 下述格式之一:
    1. 至少一位数字,后面跟着一个点 '.'
    2. 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
    3. 一个点 '.' ,后面跟着至少一位数字

整数(按顺序)可以分成以下几个部分:

  1. (可选)一个符号字符('+' 或 '-'
  2. 至少一位数字

思路概述:看到这道题,就会想到枚举枚举,因为脑袋里貌似还真没有合适的算法适配它,所以最后还是毅然决然选择了暴力枚举。显然这道题正向枚举肯定情况太多了,毕竟有很多很多搭配,所以要枚举大概率还是反向枚举合适,即:不符合条件的情况返回false,其他的情况返回true。

        当然,由题目的描述可以知道,字符串中有说空格开头和空格结尾的情况,为了避免麻烦,我将这一部分跳出,选择直接判断中间的字符串,而字符串中可能出现的字符为正负号'+'、'-',小数点'.',指数'e'、‘E',还有就是数字了,然后从这几种类型出发来进行枚举。

bool isNumber(char* s){
    bool isnum=false,ise=false,ispot=false,issign=false;//判断上一个位置的字符类型
    bool pot=false,e=false;//判断之前是否已经出现过小数点或者'e'、'E'
    int leng = strlen(s);
    int head=0;
    int tail;
    for(;head<leng;head++){//记录非空格字符串的起点
        if(s[head]!=' '){
            break;
        }
    }
    if(head == leng){
        return false;
    }
    for(tail=head;tail<leng;tail++){//记录非空格字符串的重点
        if(s[tail]==' '){
            break;
        }
    }
    for(int i=tail;i<leng;i++){
        if(s[i]!=' '){
            return false;
        }
    }
    for(int i=head;i<tail;i++){
        if(s[i]=='+'||s[i]=='-'){//指针位置为正负号
            if((!ise&&i!=head)||isnum||ispot||issign){
                return false;
            }
            else if(ise){
                if(!(s[i+1]>='0'&&s[i+1]<='9')){
                    return false;
                }
            }
            else{
                if(ise){
                    ise = false;
                }
                issign = true;
            }
        }
        else if(s[i] == '.'){//指针位置为小数点
            if(pot||e){
                return false;
            }
            else{
                if(isnum){
                    ispot = true;
                    isnum = false;
                }
                else{
                    if(s[i+1]>='0'&&s[i+1]<='9'){
                        if(issign){
                            issign = false;
                            ispot = true;
                        }
                        else if(i == head){
                            ispot = true;
                        }
                        else{
                            return false;
                        }
                    }
                    else{
                        return false;
                    }
                }
            }
            pot = true;
        }
        else if(s[i] == 'e' ||s[i] =='E'){//指针位置为'e'或者'E'
            if(e){
                return false;
            }
            if(!isnum&&!ispot){
                return false;
            }
            ise = true;
            isnum = false;
            ispot = false;
            e = true;
            if((s[i+1]>='0'&&s[i+1]<='9')||s[i+1]=='+'||s[i+1]=='-'){
            }
            else{
                return false;
            }
        }
        else if(s[i] >= '0'&&s[i] <= '9'){//指针位置为数字
            isnum = true;
            ise = false;
            ispot = false;
            issign = false;
        }
        else{//指针位置为其他的不在定义范围的字符
            return false;
        }
    }
    return true;
}

         当然,自己的暴力解法结束了就要开始学习其他人的方法了,我发现官方解答给了一种规范的枚举策略——有限状态自动机,他将其中的所有可以枚举的东西都列举了出来,这种策略用于大规模的程序中肯定是优势远大于我这种直接性的暴力枚举。

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,
    STATE_ILLEGAL
};

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

enum CharType toCharType(char ch) {
    if (ch >= '0' && ch <= '9') {
        return CHAR_NUMBER;
    } else if (ch == 'e' || ch == 'E') {
        return CHAR_EXP;
    } else if (ch == '.') {
        return CHAR_POINT;
    } else if (ch == '+' || ch == '-') {
        return CHAR_SIGN;
    } else if (ch == ' ') {
        return CHAR_SPACE;
    } else {
        return CHAR_ILLEGAL;
    }
}

enum State transfer(enum State st, enum CharType typ) {
    switch (st) {
        case STATE_INITIAL: {
            switch (typ) {
                case CHAR_SPACE:
                    return STATE_INITIAL;
                case CHAR_NUMBER:
                    return STATE_INTEGER;
                case CHAR_POINT:
                    return STATE_POINT_WITHOUT_INT;
                case CHAR_SIGN:
                    return STATE_INT_SIGN;
                default:
                    return STATE_ILLEGAL;
            }
        }
        case STATE_INT_SIGN: {
            switch (typ) {
                case CHAR_NUMBER:
                    return STATE_INTEGER;
                case CHAR_POINT:
                    return STATE_POINT_WITHOUT_INT;
                default:
                    return STATE_ILLEGAL;
            }
        }
        case STATE_INTEGER: {
            switch (typ) {
                case CHAR_NUMBER:
                    return STATE_INTEGER;
                case CHAR_EXP:
                    return STATE_EXP;
                case CHAR_POINT:
                    return STATE_POINT;
                case CHAR_SPACE:
                    return STATE_END;
                default:
                    return STATE_ILLEGAL;
            }
        }
        case STATE_POINT: {
            switch (typ) {
                case CHAR_NUMBER:
                    return STATE_FRACTION;
                case CHAR_EXP:
                    return STATE_EXP;
                case CHAR_SPACE:
                    return STATE_END;
                default:
                    return STATE_ILLEGAL;
            }
        }
        case STATE_POINT_WITHOUT_INT: {
            switch (typ) {
                case CHAR_NUMBER:
                    return STATE_FRACTION;
                default:
                    return STATE_ILLEGAL;
            }
        }
        case STATE_FRACTION: {
            switch (typ) {
                case CHAR_NUMBER:
                    return STATE_FRACTION;
                case CHAR_EXP:
                    return STATE_EXP;
                case CHAR_SPACE:
                    return STATE_END;
                default:
                    return STATE_ILLEGAL;
            }
        }
        case STATE_EXP: {
            switch (typ) {
                case CHAR_NUMBER:
                    return STATE_EXP_NUMBER;
                case CHAR_SIGN:
                    return STATE_EXP_SIGN;
                default:
                    return STATE_ILLEGAL;
            }
        }
        case STATE_EXP_SIGN: {
            switch (typ) {
                case CHAR_NUMBER:
                    return STATE_EXP_NUMBER;
                default:
                    return STATE_ILLEGAL;
            }
        }
        case STATE_EXP_NUMBER: {
            switch (typ) {
                case CHAR_NUMBER:
                    return STATE_EXP_NUMBER;
                case CHAR_SPACE:
                    return STATE_END;
                default:
                    return STATE_ILLEGAL;
            }
        }
        case STATE_END: {
            switch (typ) {
                case CHAR_SPACE:
                    return STATE_END;
                default:
                    return STATE_ILLEGAL;
            }
        }
        default:
            return STATE_ILLEGAL;
    }
}

bool isNumber(char* s) {
    int len = strlen(s);
    enum State st = STATE_INITIAL;

    for (int i = 0; i < len; i++) {
        enum CharType typ = toCharType(s[i]);
        enum State nextState = transfer(st, typ);
        if (nextState == STATE_ILLEGAL) return false;
        st = nextState;
    }
    return st == STATE_INTEGER || st == STATE_POINT || st == STATE_FRACTION || st == STATE_EXP_NUMBER || st == STATE_END;
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/biao-shi-shu-zhi-de-zi-fu-chuan-lcof/solutions/372095/biao-shi-shu-zhi-de-zi-fu-chuan-by-leetcode-soluti/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值