剑指Offer——表示数值的字符串

题目描述:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

         方法一(字符串匹配):表示字符串遵循模式A[.[B]][e|EC]或者.B[e|EC],A是整数部分,B是小数点部分,C是紧跟着E|e的数值。A和C是带正负号的整数,且正负号位于A和C的首部,且B是不带正负号的整数
        1.先看整数,按照有符号数的方法逐位比较。如果出现小数点,则说明进入小数部分,如果出现e,则说明进入指数部分
        2.进入小数部分后,按照无符号数进行比较,比较完之后,要想判断是否是数值,需要和整数部分综合考量,才能判断是否是数值。会出现三种情况:(1)整数是真,小数是真,是真  (2)整数真 小数假 是真  (3)整数真,小数假 是真。  将小数判断放在前面
        3.进入指数部分,按照有符号数的方式比较,要想这个字符串必须是真,必须是前面部分表示为真,e|E后面表示为真
        4.不能直接返回上面整合的判断值,因为上面的情况下只判断了+,-,0~9,小数点和e这几种情况是否是数值,如果出现其他符号,index是不会++的,最后返回的时候,要判断index是否指向最后一位(因为出现a的话,index会停在a处,表示a以前的字符串不是一个数值)

public class Solution {
    private int index=0;
    public boolean isNumeric(char[] str) {
       if(str.length<1){
           return false;
       }
        //判断是否符合整数的 
        boolean flag=scanInteger(str);
        //判断小数部分
        if(index<str.length && str[index]=='.'){
            index++;
            //这个就是上面说的小数部分会出现的三种情况
            //1.小数假,整数位真,为真,也就是整数部分后面没有小数,例如222.
            //2.小数真,整数位假,为真,也就是小数部分前面没有整数,例如.123
            //3.小数真,整数为真,为真,也就是小数和整数部分都有数字,例如22.2
            //不能判断整数放在前面,要不然就会不去判断小数
            flag=scanUnsignedInteger(str) || flag;
        }
        //进入指数部分
        if(index < str.length && (str[index] == 'E' || str[index] == 'e')){
            index++;
            //下面用&&的原因:
            //1.当e或E前面没有数字的时候,整个字符串不能表示数字,如.e1
            //2.当e或E后面没有整数的是,整个字符串不能表示数字,例如12E
            flag=flag && scanInteger(str);
        }
        return flag && index==str.length;
       
    }
    
    //判断有符号的数
    private boolean scanInteger(char[] str){
        if(index<str.length && (str[index]=='+' || str[index]=='-')){
            index++;
        }
        return scanUnsignedInteger(str);
    }
    //判断无符号的数
    private boolean scanUnsignedInteger(char[] str){
        int start=index;
        while(index<str.length && str[index]>='0' && str[index]<='9'){
            index++;
        }
        //如果str中有0~9的数字,返回true
        return start<index;
    } 
}

注意这个里面的&&和|| 的应用。刚开始报错是因为将进入小数部分的长度判断放在后面,这样的话index就是超出边界的。应该首先判断这个index是否小于字符串长度。

方法二(排除法):

    (1)+,-只能放在首位或者E,e的后面
           (2)E或e,以及小数点只能出现一次,并且:在有E或者e的情况下,小数点不能在E,e后面出现
           (3)不能有除了数字,E,e,小数点,+,-之外的其他字符出现
           (4)e或E后面必须出现数字,如果后面是+或-,continue,继续判单有没有数字,直到找到为止。
           (5)不能是空符号串

 public boolean isNumeric(char[] string) {
       int n=string.length;
       int cnt1=0,cnt2=0,pos1=0,pos2=0,cnt3=0,pos3=0;
        if(n==0) return false;
        for(int i=0;i<n;i++){
            //这个字符串中不能出现其他字符,出现了直接返回false
        if(string[i]!='e' && string[i]!='E'&&!(string[i]>='0'&&string[i]<='9')&&string[i]!='.'&&string[i]!='+'&&string[i]!='-')
            return false;
            //记录小数点的个数和位置
        if(string[i]=='.') {
            cnt1++;
            pos1 = i;
        }
            //记录e|E出现的个数或者位数
        if(string[i]=='e'||string[i]=='E') {
            cnt2++;
            pos2 = i;
        }
            //记录符号数的个数或者位数
        if(string[i]=='+'||string[i]=='-') {
            cnt3++;
            pos3 = i;
        }
    }
        //如果指数和小数点和符号数都出现多个
        if(cnt2>=2||cnt1>=2||cnt3>=3) return false;
        //如果指数出现在小数点之前
        if(pos1>pos2&&cnt2!=0)return false;
        //第一个字符是符号,符号的个数减1
        if(string[0]=='+'||string[0]=='-')
        {
            cnt3--;
        }
        //如果指数后面的有符号,符号数减去1,很有一种情况,指数后面没有数字,所以要判断与字符串的大小
        if(cnt2>0  && pos2+1<string.length && (string[pos2+1]=='+'||string[pos2+1]=='-')) {
            cnt3--;
        }
        //如果符号数还有,说明不对
        if(cnt3>0) {
            return false;
        }
        //指数后面的
        if(cnt2>0){
        int flag=0;
        for(int i=pos2+1;i<n;i++){
            if(string[i]=='+'||string[i]=='-') continue;
            if(string[i]>='0'&& string[i]<='9'){
                flag=1;
                break;
            }
        }
        if(flag==0) return false;
    }
        return true;
    }

方法三:正则表达式

import java.util.regex.Pattern;
public class Solution {
    public boolean isNumeric(char[] str) {
        String pattern = "^[-+]?\\d*(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?$";
        String s = new String(str);
        return Pattern.matches(pattern,s);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值