题目:
Validate if a given string is numeric.
Some examples:
“0” => true
” 0.1 ” => true
“abc” => true
“2e10” => true
思路:
方法1 :直接使用正则表达式regx = “[-+]?(\d+\.?|\.\d+)\d*(e[-+]?\d+)?”,简单粗暴!
方法2 :如果不用正则,就采用 确定有穷状态自动机(DFA),代码简洁有效。不过这里要提前了解一点图论知识。
所谓“确定有穷状态”,必然需要我们自己动手构造出所有状态来,如下所示:
* 0 初始无输入或者只有space的状态
* 1 输入了数字之后的状态
* 2 前面无数字,只输入了dot的状态
* 3 输入了+/-状态
* 4 前面有数字和有dot的状态
* 5 'e' or 'E'输入后的状态
* 6 输入e之后输入+/-的状态
* 7 输入e后输入数字的状态
输入类型我们定义为:
INVALID, // 1. invalid input
SIGN,// 2. ‘+’ or ‘-’
DIGIT,// 3. digits
DOT,// 4. ‘.’
EXP// 5. ‘e’
一共8种状态,然后我们需要根据状态来确定它们的转移,如下图所示:
在9种状态中,我们可以发现只有1、4、7四种状态是合法的,所以题目迎刃而解,只要挨个遍历字符,通过判断遍历到最后一个字符时的状态即可确定该字符串是否合法。 在编程中,我们可以简单地用一个邻接矩阵来存储上图转移关系。 这里,我们用个二维数组来表示这表示这个状态转移矩阵。
代码
方法1:
public class Solution {
/**
* 判断指定字符串是否为数字
* @param s 字符串
* @return true:是数字 false:不是数字
*/
public boolean isNumber(String s) {
s = s.trim();
if (s.isEmpty()) {
return false;
}
//正则匹配
Pattern p = Pattern.compile(
"^([+-])?((\\d+)(\\.)?(\\d+)?|(\\d+)?(\\.)?(\\d+))(e([+-])?(\\d+))?$");
Matcher m = p.matcher(s);
if (m.find()) {
return true;
}
return false;
}
}
方法2:
public class ReserveWord {
final int INVALID = 0;
final int SIGN = 1;
final int DIGIT = 2;
final int DOT = 3;
final int EXP = 4;
final int[][] transitionTable = {
{-1, 3, 1, 2, -1},
{-1, -1, 1, 4, 5},
{-1, -1, 4, -1, -1},
{-1, -1, 1, 2, -1},
{-1, -1, 4, -1, 5},
{-1, 6, 7, -1, -1},
{-1, -1, 7, -1, -1},
{-1, -1, 7, -1, -1},
{-1, -1, 7, -1, -1}
};
int state = 0;
public boolean isNumber(String s) {
if (s == null && s.equals(" ")) {
return false;
}
s = s.trim();
for (int i = 0; i < s.length(); ++i) {
int type = INVALID;
if (s.charAt(i) == '+' || s.charAt(i) == '-') {
type = SIGN;
} else if (Character.isDigit(s.charAt(i))) {
type = DIGIT;
} else if (s.charAt(i) == '.') {
type = DOT;
} else if (s.charAt(i) == 'e' || s.charAt(i) == 'E') {
type = EXP;
}
state = transitionTable[state][type];
System.out.println(state);
if (state == -1) return false;
}
return state == 1 || state == 4 || state == 7;
}
};