Here is my alternative solution, instead of scan through the string with different states, I partition the string first into smaller pieces which can decide individually easily.

public class Solution {
public boolean isSignedIntegerNumeric(String s, int start, int end, boolean allowEmpty) {
if(start>end)
return allowEmpty;
if(s.charAt(start)=='-' || s.charAt(start)=='+')
start++;
return isUnsignedIntegerNumeric(s, start, end, allowEmpty);
}
public boolean isUnsignedIntegerNumeric(String s, int start, int end, boolean allowEmpty) {
if(start>end)
return allowEmpty;
for(int k=start; k<=end; k++)
if(s.charAt(k)<'0' || s.charAt(k)>'9')
return false;
return true;
}
public boolean isNumeric(String s, int start, int end) {
int dotIdx = s.indexOf(".", start);
if(dotIdx != s.lastIndexOf(".", end))
return false;
if(dotIdx==-1) {
return isSignedIntegerNumeric(s, start, end, false);
} else {
if(dotIdx==end)
return isSignedIntegerNumeric(s, start, dotIdx-1, false);
else
return isSignedIntegerNumeric(s, start, dotIdx-1, true) &&
isUnsignedIntegerNumeric(s, dotIdx+1, end, false);
}
}
public boolean isNumber(String s) {
if(s.isEmpty())
return false;
s = s.trim();
int eIdx = s.indexOf("e");
if(eIdx != s.lastIndexOf("e"))
return false;
if(eIdx==-1) {
return isNumeric(s, 0, s.length()-1);
} else {
return isNumeric(s, 0, eIdx-1) &&
isSignedIntegerNumeric(s, eIdx+1, s.length()-1, false);
}
}
}