原题网址:https://leetcode.com/problems/valid-number/
Validate if a given string is numeric.
Some examples:
"0"
=> true
" 0.1 "
=> true
"abc"
=> false
"1 a"
=> false
"2e10"
=> true
Note: It is intended for the problem statement to be ambiguous. You should gather all requirements up front before implementing one.
Update (2015-02-10):
The signature of the C++
function had been updated. If you still see your function signature accepts a const char *
argument, please click the reload button to reset your code definition.
思路:使用有限状态自动机。
方法一:使用完整的有限状态自动机。
public class Solution {
private int accept = 9;
private NFA nfa = new NFA();
{
nfa.put(0, null, 1);
nfa.put(1, ' ', 1);
nfa.put(1, '+', 2);
nfa.put(1, '-', 2);
nfa.put(1, null, 2);
for(char ch='0'; ch<='9'; ch++) nfa.put(2, ch, 3);
for(char ch='0'; ch<='9'; ch++) nfa.put(3, ch, 3);
nfa.put(3, '.', 4);
for(char ch='0'; ch<='9'; ch++) nfa.put(4, ch, 4);
nfa.put(4, null, 5);
nfa.put(3, null, 5);
nfa.put(2, '.', 10);
for(char ch='0'; ch<='9'; ch++) nfa.put(10, ch, 11);
for(char ch='0'; ch<='9'; ch++) nfa.put(11, ch, 11);
nfa.put(11, null, 5);
nfa.put(5, 'e', 6);
nfa.put(5, 'E', 6);
nfa.put(6, '+', 7);
nfa.put(6, '-', 7);
nfa.put(6, null, 7);
for(char ch='0'; ch<='9'; ch++) nfa.put(7, ch, 8);
for(char ch='0'; ch<='9'; ch++) nfa.put(8, ch, 8);
nfa.put(8, null, 9);
nfa.put(5, null, 9);
nfa.put(9, ' ', 9);
}
public boolean isNumber(String s) {
Set<Integer> states = new HashSet<>();
states.add(0);
states = nfa.getClosure(states);
for(int i=0; i<s.length(); i++) {
Set<Integer> nexts = new HashSet<>();
for(Integer state: states) {
nexts.addAll(nfa.get(state, s.charAt(i)));
}
states = nfa.getClosure(nexts);
// System.out.printf("[%d]%c, states=%s\n", i, s.charAt(i), states);
}
return states.contains(accept);
}
}
class NFA {
public Map<Integer, Map<Character, List<Integer>>> transitions = new HashMap<>();
Set<Integer> getClosure(Set<Integer> states) {
Set<Integer> closure = new HashSet<>();
closure.addAll(states);
Set<Integer> found = new HashSet<>();
found.addAll(states);
while (!found.isEmpty()) {
Set<Integer> epsilons = new HashSet<>();
for(Integer state: found) {
List<Integer> epsilon = transitions.get(state).get(null);
if (epsilon != null ) {
closure.addAll(epsilon);
epsilons.addAll(epsilon);
}
}
found = epsilons;
}
return closure;
}
public void put(int state, Character ch, int next) {
Map<Character, List<Integer>> transition = transitions.get(state);
if (transition == null) {
transition = new HashMap<Character, List<Integer>>();
transitions.put(state, transition);
}
List<Integer> nexts = transition.get(ch);
if (nexts == null) {
nexts = new ArrayList<>();
transition.put(ch, nexts);
}
nexts.add(next);
}
Set<Integer> get(int state, char ch) {
Map<Character, List<Integer>> transition = transitions.get(state);
if (transition == null) return new HashSet<>();;
List<Integer> nexts = transition.get(ch);
if (nexts == null) return new HashSet<>();
return new HashSet<>(nexts);
}
}
方法二:使用简化的状态机。
public class Solution {
public boolean isNumber(String s) {
char[] sa = s.toCharArray();
int state = 0;
for(int i=0; i<sa.length; i++) {
switch (state) {
case 0:
if (sa[i] == ' ') continue;
if (sa[i] == '+' || sa[i] == '-') { state = 1; continue; }
if (sa[i] >= '0' && sa[i] <= '9') { state = 2; continue; }
if (sa[i] == '.') { state = 3; continue; }
return false;
case 1:
if (sa[i] == '.') { state = 3; continue; }
if (sa[i] >= '0' && sa[i] <= '9') { state = 2; continue; }
return false;
case 2:
if (sa[i] ==' ') { state = 8; continue; }
if (sa[i] == '.') { state = 4; continue; }
if (sa[i] >= '0' && sa[i] <= '9') continue;
if (sa[i] == 'e' || sa[i] == 'E') { state = 5; continue; }
return false;
case 3:
if (sa[i] >= '0' && sa[i] <= '9') { state = 4; continue; }
return false;
case 4:
if (sa[i] == 'e' || sa[i] == 'E') { state = 5; continue; }
if (sa[i] == ' ') { state = 8; continue; }
if (sa[i] >= '0' && sa[i] <= '9') continue;
return false;
case 5:
if (sa[i] == '+' || sa[i] == '-') { state = 6; continue; }
if (sa[i] >= '0' && sa[i] <= '9') { state = 7; continue; }
return false;
case 6:
if (sa[i] >= '0' && sa[i] <= '9') { state = 7; continue; }
return false;
case 7:
if (sa[i] >= '0' && sa[i] <= '9') continue;
if (sa[i] == ' ') { state = 8; continue; }
return false;
case 8:
if (sa[i] == ' ') continue;
return false;
default:
return false;
}
}
if (state == 2 || state == 4 || state == 7 || state == 8) return true;
return false;
}
}