这道题目的解法很多:

  1. 正则匹配
  2. Java类库
  3. 条件判断
  4. 有限状态机

我一开始想的解法是条件判断,后来对其进行了修改,使用了自上而下的递归:

import java.util.*;

public class Solution {
    // 合法字符集, E视同e,因此不纳入该集合
    private Set<Character> legalChars = new HashSet<>(Arrays.asList(
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        '+', '-', '.', 'e'));

    public boolean isNumeric (String str) {
        if (str == null || str.length() == 0)
            return false;

        str = str.toLowerCase(); // E视同e,简化后续逻辑
        char[] charArr = str.toCharArray();
        if (hasIllegalChar(charArr) // 排除不合法的字符的影响
           || hasCharMoreThan(charArr, '.', 1) // .的个数不能超过1
           || hasCharMoreThan(charArr, 'e', 1)) { // e的个数不能超过1
            return false;
        }

        // 开始递归的时候已经进行了筛检,剩下的字符串只有合法字符,至多一个'.',至多一个'e'
        return doDudge(str);
    }

    // 递归辅助函数
    private boolean doDudge(String str) {
        if (str == null || str.length() == 0)
            return false;
        if (str.contains("e")) {
            // 自上而下的递归,在开始递归前,确保'.'只能出现在'e'的左侧,且不能以'e'结尾
            if (str.endsWith("e") || str.indexOf('.') > str.indexOf('e'))
                return false;
            return doDudge(str.split("e")[0]) && doDudge(str.split("e")[1]); 
        } else if (str.startsWith("+") || str.startsWith("-")) {
            // 针对没有'e'或有'e'但是递归拆分下来的场景,确保开头最多出现一个'+'或'-'
            if (str.length() == 1 || str.charAt(1) == '+' || str.charAt(1) == '-')
                return false;
            // 忽略开头的'+'或者'-',继续向后递归处理
            return doDudge(str.substring(1));
        } else {
            // 递归剥离了'e'和开头的'+', '-',禁止还存在'+', '-',禁止以'.'结尾,其余均合法
            return !str.endsWith(".") && !str.contains("+") && !str.contains("-");
        }
    }

    // 辅助函数,判断一个数组中是否存在超过count个字符c
    private boolean hasCharMoreThan(char[] arr, char c, int count) {
        int cnt = 0;
        for (char ch : arr) {
            if (ch == c) {
                ++cnt;
            }
        }
        if (cnt > count)
            return true;
        return false;
    }

    // 辅助函数,判断字符数组中是否存在合法字符以外的字符
    private boolean hasIllegalChar(char[] arr) {
        for (char c : arr) {
            if (!legalChars.contains(c)) {
                return true;
            }
        }
        return false;
    }
}