力扣第六十五题-有效数字

366 阅读2分钟

「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

前言

力扣第六十五题 有效数字 如下所示:

image.png

示例 1:

输入: s = "0"
输出: true

示例 2:

输入: s = "e"
输出: false

示例 3:

输入: s = "."
输出: false

示例 4:

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

一、思路

这一题如果在日常的开发过程中我大概率会使用 正则表达式 来校验某个字符串是不是有效的数字。但考虑到这是一道算法练习题,所以就用别的方式了。

这一题我是使用 穷举 的方式来实现的,其中最值得关心的情况就是 字符串中是否有且仅有一个科学计数法的 e,且 e 的位置不在头或尾部

  • 如果含有 e :判断 e 前面是否为整数或小数,e 后面是否为整数
  • 如果不含有 e:判断该字符串是否为整数或小数

举个例子

此处就以稍微复杂一点的 str = +.3e-10 作为例子

  1. e 作为标记,将字符串分为 +.3-10
  2. 易知,e 前面的 +.3 满足小数的标准
  3. 易知,e 后面的 -10 满足整数的标准
  4. 综上所述,+.3e-10 为一个有效的数字

二、实现

实现代码

代码虽然比较长,但是都有注释,且将公共的地方提出来做成了公用的方法。总体上是比较好理解的,故不作过多解释。

    /**
     * 复杂情况模拟
     */
    public boolean isNumber(String s) {
        char[] chars = s.toCharArray();
        int ePosition = -1; // e的位置
        for (int i=0; i<chars.length; i++) {
            // 找有没有 e
            char c = chars[i];
            if (c == 'e' || c == 'E') {
                ePosition = i;
                break;
            }
        }
        // 判断e前面部分是否正确
        if (ePosition != -1) {  // 有科学计数标识
            // e 不能在头或尾
            if (ePosition == 0 || ePosition == chars.length -1) {
                return false;
            }
            // e的后面不能是一个单独的加号或减号
            if (chars.length - ePosition == 2 && (chars[ePosition + 1] == '+' || chars[ePosition + 1] == '-')) {
                return false;
            }
            // e的前面不能是一个单独的加号或减号
            if (ePosition == 1 && (chars[0] == '+' || chars[0] == '-')) {
                return false;
            }
            return isDecimalOrInteger(chars, ePosition) && isInteger(chars, true, ePosition + 1, chars.length);
        } else {
            return isDecimalOrInteger(chars, chars.length);
        }
    }

    /**
     * 区间:左开右闭
     */
    private boolean isDecimalOrInteger(char[] chars , int end) {
        int dotPosition = -1;
        // 判断是否有点
        for (int i =0; i<end; i++) {
            if (chars[i] == '.') {
                dotPosition = i;
                break;
            }
        }
        // 至少一位数字,后面跟着一个点 '.'
        // 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
        // 一个点 '.' ,后面跟着至少一位数字
        if (dotPosition == 0 && end == 1 || (dotPosition == end -1 && (chars[dotPosition-1] < '0' || chars[dotPosition-1] > '9'))) {
            return false;
        } else if (dotPosition != -1) {
            return isInteger(chars, true, 0, dotPosition) && isInteger(chars, false, dotPosition + 1, end);
        } else {
            return isInteger(chars, true, 0, end);
        }
    }

    /**
     * 区间:左开右闭
     */
    private boolean isInteger(char[] chars, boolean withSymbol, int start, int end) {
        for (int i=start; i<end; i++) {
            char c = chars[i];
            if (withSymbol && i == start && (c == '-' || c == '+')) {
                continue;
            }else if (c < '0' || c > '9') {
                return false;
            }
        }
        return true;
    }

测试代码

public static void main(String[] args) {
    String str = "+.3e-10";
    boolean flag = new Number65().isNumber(str);
    System.out.println(flag);
}

结果

image.png

三、总结

用逻辑推理的方式,真的是一直在Debug。我总共提交了快20次,才能够通过所有的测试用例。

image.png

后面看了官方的题解,有限状态机是一个更好的实现方式,逻辑也会更清晰!

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~