剑指offer-判断字符串是否表示数值

题目:表示数值的字符串

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

例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

 

思路分析:

问题就是判断给出的字符串是否能合法地表示数值

字符串从左到右遍历判断如下,位置指针从0开始,设置标志flag的目的是从前到后标识字符串中的每一部分是否合法:

(1)是否有正负号,有的话指针后移一位,继续往后判断,没有就跳过该步骤,继续判断

(2)如果是数字的话,指针相应后移对应的位数,将标志flag置为true,是其他的话置为false,继续往后判断

(3)如果是小数点的话,对小数点后的字符进行步骤(2)判断,返回当前flag || 小数点后步骤(2)的结果 ,继续往后判断

    (此处用或连接两部分结果,因为小数点前后都可以只有一面有数字)

(4)如果是e或是E的话,返回当前flag&&e或E后面再进行步骤(1)(2)的结果

    (此处用与连接两部分内容,是因为e的前后都必须要有数字,后面的数字可以带符号)

(5)如果此时flag为真,同时字符串已到了末尾,返回真,否则为假

 

代码如下:

public class Solution {
    private int index = 0;
    
    public boolean isNumeric(char[] str) {
        if (str.length==0) return false;
        boolean flag = scanInteger(str);
        
        // 如果出现'.',接下来是数字的小数部分
        if (index < str.length && str[index] == '.') {
            index++;
            // 下面一行代码用||的原因:
            // 1. 小数可以没有整数部分,例如.123等于0.123;
            // 2. 小数点后面可以没有数字,例如233.等于233.0;
            // 3. 当然小数点前面和后面可以有数字,例如233.666
            flag = scanUnsignedInteger(str) || flag;
        }
        
        // 如果出现'e'或者'E',接下来跟着的是数字的指数部分
        if (index < str.length && (str[index] == 'E' || str[index] == 'e')) {
            index++;
            // 下面一行代码用&&的原因:
            // 1. 当e或E前面没有数字时,整个字符串不能表示数字,例如.e1、e1;
            // 2. 当e或E后面没有整数时,整个字符串不能表示数字,例如12e、12e+5.4
            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; 
    }
}

上面是《剑指offer》上的标准解法,好的解法总让人看起来心旷神怡,感到精妙无比。

当然,也有使用正则表达式的解法:

public class Solution {
    public boolean isNumeric(char[] str) {
        String string = String.valueOf(str);
        return string.matches("[\\+\\-]?\\d*(\\.\\d+)?([eE][\\+\\-]?\\d+)?");
    }
}
/*
以下对正则进行解释:
[\\+\\-]?            -> 正或负符号出现与否
\\d*                 -> d的含义和[0-9]一样。它匹配一个数字,后缀 * 指引它可匹配零个或者多个数字,如-.34 或 +3.34均符合
(\\.\\d+)?           -> 如果出现小数点,那么小数点后面必须有数字,否则一起不出现;正则表达式中 * 号表示前一个位置出现0次或多次, 
             -> +号表示前一个位置出现1次或多次
([eE][\\+\\-]?\\d+)? -> 如果存在指数部分,那么e或E肯定出现,+或-可以不出现, 紧接着必须跟着整数;或者整个部分都不出现
 
正则表达式中,^ 和 美元符号$框定正则表达式,它指引这个正则表达式对文本中的所有字符都进行匹配。如果省略这些标识,
那么只要一个字符串中包含一个数字这个正则表达式就会进行匹配。如果仅包含 ^ ,它将匹配以一个数字开头的字符串。如果仅包含$ ,则匹配以一个数字结尾的字符串。
*/

 

posted @ 2020-03-13 11:42  pathjh  阅读(195)  评论(0编辑  收藏  举报