表驱动法
发布于 2019-06-1022.9k精选JavaJavaScript
本题可以采用《编译原理》里面的确定的有限状态机(DFA)解决。构造一个DFA并实现,构造方法可以先写正则表达式,然后转为 DFA,也可以直接写,我就是直接写的,虽然大概率不会是最简结构(具体请参考《编译器原理》图灵出版社),不过不影响解题。DFA 作为确定的有限状态机,比 NFA 更加实用,因为对于每一个状态接收的下一个字符,DFA 能确定唯一一条转换路径,所以使用简单的表驱动的一些方法就可以实现,并且只需要读一遍输入流,比起 NFA 需要回读在速度上会有所提升。
构建出来的状态机如封面图片所示(红色为 终止状态,蓝色为 中间状态)。根据《编译原理》的解释,DFA 从状态 0 接受串 s 作为输入。当s耗尽的时候如果当前状态处于中间状态,则拒绝;如果到达终止状态,则接受。
然后,根据 DFA 列出如下的状态跳转表,之后我们就可以采用 表驱动法 进行编程实现了。需要注意的是,这里面多了一个状态 8,是用于处理串后面的若干个多余空格的。所以,所有的终止态都要跟上一个状态 8。其中,有一些状态标识为-1,是表示遇到了一些意外的字符,可以直接停止后续的计算。状态跳转表如下:
state | blank | +/- | 0-9 | . | e | other |
---|---|---|---|---|---|---|
0 | 0 | 1 | 6 | 2 | -1 | -1 |
1 | -1 | -1 | 6 | 2 | -1 | -1 |
2 | -1 | -1 | 3 | -1 | -1 | -1 |
3 | 8 | -1 | 3 | -1 | 4 | -1 |
4 | -1 | 7 | 5 | -1 | -1 | -1 |
5 | 8 | -1 | 5 | -1 | -1 | -1 |
6 | 8 | -1 | 6 | 3 | 4 | -1 |
7 | -1 | -1 | 5 | -1 | -1 | -1 |
8 | 8 | -1 | -1 | -1 | -1 | -1 |
状态图:
- Java
-
class Solution { public int make(char c) { switch(c) { case ' ': return 0; case '+': case '-': return 1; case '.': return 3; case 'e': return 4; default: if(c >= 48 && c <= 57) return 2; } return -1; } public boolean isNumber(String s) { int state = 0; int finals = 0b101101000; int[][] transfer = new int[][]{{ 0, 1, 6, 2,-1}, {-1,-1, 6, 2,-1}, {-1,-1, 3,-1,-1}, { 8,-1, 3,-1, 4}, {-1, 7, 5,-1,-1}, { 8,-1, 5,-1,-1}, { 8,-1, 6, 3, 4}, {-1,-1, 5,-1,-1}, { 8,-1,-1,-1,-1}}; char[] ss = s.toCharArray(); for(int i=0; i < ss.length; ++i) { int id = make(ss[i]); if (id < 0) return false; state = transfer[state][id]; if (state < 0) return false; } return (finals & (1 << state)) > 0; } } 作者:user8973 链接:https://leetcode-cn.com/problems/valid-number/solution/biao-qu-dong-fa-by-user8973/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- JavaScript
var isNumber = function(s) {
let state = 0,
finals = [0,0,0,1,0,1,1,0,1],
transfer = [[ 0, 1, 6, 2,-1,-1],
[-1,-1, 6, 2,-1,-1],
[-1,-1, 3,-1,-1,-1],
[ 8,-1, 3,-1, 4,-1],
[-1, 7, 5,-1,-1,-1],
[ 8,-1, 5,-1,-1,-1],
[ 8,-1, 6, 3, 4,-1],
[-1,-1, 5,-1,-1,-1],
[ 8,-1,-1,-1,-1,-1]],
make = (c) => {
switch(c) {
case " ": return 0;
case "+":
case "-": return 1;
case ".": return 3;
case "e": return 4;
default:
let code = c.charCodeAt();
if(code >= 48 && code <= 57) {
return 2;
} else {
return 5;
}
}
};
for(let i=0; i < s.length; ++i) {
state = transfer[state][make(s[i])];
if (state < 0) return false;
}
return finals[state];
};