验证给定的字符串是否可以解释为十进制数字。
例如:
"0" => true
" 0.1 " => true
"abc" => false
"1 a" => false
"2e10" => true
" -90e3 " => true
" 1e" => false
"e3" => false
" 6e-1" => true
" 99e2.5 " => false
"53.5e93" => true
" --6 " => false
"-+3" => false
"95a54e53" => false
说明:
我们有意将问题陈述地比较模糊。在实现代码之前,你应当事先思考所有可能的情况。这里给出一份可能存在于有效十进制数字中的字符列表:
数字 0-9
指数 - “e”
正/负号 - “+”/“-“
小数点 - “.”
当然,在输入中,这些字符的上下文也很重要。
代码
- 直接来,设计以下错误识别方式
class Solution {
public boolean isNumber(String s) {
s = s.trim();
boolean pointSeen = false;
boolean eSeen = false;
boolean numberSeen = false;
boolean numberAfterE = true;
for (int i = 0;i < s.length();i++) {
if (s.charAt(i) <= '9' && s.charAt(i) >= '0') {
numberSeen = true;
numberAfterE = true;
} else if (s.charAt(i) == '.'){
if(eSeen || pointSeen) {
return false;
}
pointSeen = true;
} else if (s.charAt(i) == 'e') {
if (eSeen || !numberSeen) {
return false;
}
numberAfterE = false;
eSeen = true;
} else if (s.charAt(i) == '-' || s.charAt(i) == '+') {
if (i != 0 && s.charAt(i-1) != 'e') {
return false;
}
} else {
return false;
}
}
return numberAfterE && numberSeen;
}
}
// 巧妙设计以下错误识别方法,遍历过程中,把遇到不符合的都返回 false,到最后成功到达末尾就返回 true。C++ 的代码
bool isNumber(const char *s)
{
int i = 0;
// skip the whilespaces
for(; s[i] == ' '; i++) {}
// check the significand
if(s[i] == '+' || s[i] == '-') i++; // skip the sign if exist
// nm:数字 pt:小数点
int n_nm, n_pt;
for(n_nm=0, n_pt=0; (s[i]<='9' && s[i]>='0') || s[i]=='.'; i++)
s[i] == '.' ? n_pt++:n_nm++;
if(n_pt>1 || n_nm<1) // no more than one point, at least one digit
return false;
// check the exponent if exist
if(s[i] == 'e') {
i++;
if(s[i] == '+' || s[i] == '-') i++; // skip the sign
int n_nm = 0; // 数字
for(; s[i]>='0' && s[i]<='9'; i++, n_nm++) {}
if(n_nm<1)
return false;
}
// skip the trailing whitespaces
for(; s[i] == ' '; i++) {}
return s[i]==0; // must reach the ending 0 of the string
}
// 作者:windliang
// 链接:https://leetcode-cn.com/problems/valid-number/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-1-4/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
确定无限自动机,设计状态跳转表
DFA 作为确定的有限状态机,比 NFA 更加实用,因为对于每一个状态接收的下一个字符,DFA 能确定唯一一条转换路径,所以使用简单的表驱动的一些方法就可以实现,并且只需要读一遍输入流,比起 NFA 需要回读在速度上会有所提升。
构建出来的状态机如封面图片所示(红色为 终止状态,蓝色为 中间状态)。根据《编译原理》的解释,DFA 从状态 0 接受串 s 作为输入。当s耗尽的时候如果当前状态处于中间状态,则拒绝;如果到达终止状态,则接受。
然后,根据 DFA 列出如下的状态跳转表,之后我们就可以采用 表驱动法 进行编程实现了。需要注意的是,这里面多了一个状态 8,是用于处理串后面的若干个多余空格的。所以,所有的终止态都要跟上一个状态 8。其中,有一些状态标识为-1,是表示遇到了一些意外的字符,可以直接停止后续的计算。状态跳转表如下:
作者:user8973
链接:https://leetcode-cn.com/problems/valid-number/solution/biao-qu-dong-fa-by-user8973/
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)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 采用责任链模式,各个部分负责自己的事情
/每个类都实现这个接口
interface NumberValidate {
boolean validate(String s);
}
//定义一个抽象类,用来检查一些基础的操作,是否为空,去掉首尾空格,去掉 +/-
//doValidate 交给子类自己去实现
abstract class NumberValidateTemplate implements NumberValidate{
public boolean validate(String s)
{
if (checkStringEmpty(s))
{
return false;
}
s = checkAndProcessHeader(s);
if (s.length() == 0)
{
return false;
}
return doValidate(s);
}
private boolean checkStringEmpty(String s)
{
if (s.equals(""))
{
return true;
}
return false;
}
private String checkAndProcessHeader(String value)
{
value = value.trim();
if (value.startsWith("+") || value.startsWith("-"))
{
value = value.substring(1);
}
return value;
}
protected abstract boolean doValidate(String s);
}
//实现 doValidate 判断是否是整数
class IntegerValidate extends NumberValidateTemplate{
protected boolean doValidate(String integer)
{
for (int i = 0; i < integer.length(); i++)
{
if(Character.isDigit(integer.charAt(i)) == false)
{
return false;
}
}
return true;
}
}
//实现 doValidate 判断是否是科学计数法
class SienceFormatValidate extends NumberValidateTemplate{
protected boolean doValidate(String s)
{
s = s.toLowerCase();
int pos = s.indexOf("e");
if (pos == -1)
{
return false;
}
if (s.length() == 1)
{
return false;
}
String first = s.substring(0, pos);
String second = s.substring(pos+1, s.length());
if (validatePartBeforeE(first) == false || validatePartAfterE(second) == false)
{
return false;
}
return true;
}
private boolean validatePartBeforeE(String first)
{
if (first.equals("") == true)
{
return false;
}
if (checkHeadAndEndForSpace(first) == false)
{
return false;
}
NumberValidate integerValidate = new IntegerValidate();
NumberValidate floatValidate = new FloatValidate();
if (integerValidate.validate(first) == false && floatValidate.validate(first) == false)
{
return false;
}
return true;
}
private boolean checkHeadAndEndForSpace(String part)
{
if (part.startsWith(" ") ||
part.endsWith(" "))
{
return false;
}
return true;
}
private boolean validatePartAfterE(String second)
{
if (second.equals("") == true)
{
return false;
}
if (checkHeadAndEndForSpace(second) == false)
{
return false;
}
NumberValidate integerValidate = new IntegerValidate();
if (integerValidate.validate(second) == false)
{
return false;
}
return true;
}
}
//实现 doValidate 判断是否是小数
class FloatValidate extends NumberValidateTemplate{
protected boolean doValidate(String floatVal)
{
int pos = floatVal.indexOf(".");
if (pos == -1)
{
return false;
}
if (floatVal.length() == 1)
{
return false;
}
NumberValidate nv = new IntegerValidate();
String first = floatVal.substring(0, pos);
String second = floatVal.substring(pos + 1, floatVal.length());
if (checkFirstPart(first) == true && checkFirstPart(second) == true)
{
return true;
}
return false;
}
private boolean checkFirstPart(String first)
{
if (first.equals("") == false && checkPart(first) == false)
{
return false;
}
return true;
}
private boolean checkPart(String part)
{
if (Character.isDigit(part.charAt(0)) == false ||
Character.isDigit(part.charAt(part.length() - 1)) == false)
{
return false;
}
NumberValidate nv = new IntegerValidate();
if (nv.validate(part) == false)
{
return false;
}
return true;
}
}
//定义一个执行者,我们把之前实现的各个类加到一个数组里,然后依次调用
class NumberValidator implements NumberValidate {
private ArrayList<NumberValidate> validators = new ArrayList<NumberValidate>();
public NumberValidator()
{
addValidators();
}
private void addValidators()
{
NumberValidate nv = new IntegerValidate();
validators.add(nv);
nv = new FloatValidate();
validators.add(nv);
nv = new HexValidate();
validators.add(nv);
nv = new SienceFormatValidate();
validators.add(nv);
}
@Override
public boolean validate(String s)
{
for (NumberValidate nv : validators)
{
if (nv.validate(s) == true)
{
return true;
}
}
return false;
}
}
public boolean isNumber(String s) {
NumberValidate nv = new NumberValidator();
return nv.validate(s);
}
// 作者:windliang
// 链接:https://leetcode-cn.com/problems/valid-number/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-1-4/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1056615746@qq.com