题目:
验证给定的字符串是否为数字。
例如:"0"
=> true
" 0.1 "
=> true
"abc"
=> false
"1 a"
=> false
"2e10"
=> true
说明: 我们有意将问题陈述地比较模糊。在实现代码之前,你应当事先思考所有可能的情况。
更新于 2015-02-10:C++
函数的形式已经更新了。如果你仍然看见你的函数接收 const char *
类型的参数,请点击重载按钮重置你的代码。
这道题简直就是Python 和 C++两个极致不同的体现。。。
用Python,可以通过一句话就满足所有逻辑,体现了第三方库的强大功能。。
class Solution:
def isNumber(self, s):
try:
float(s)
return True
except:
return False
是不是有点想掀桌?我当时冥思苦想想不出结果时也是这心情
而用C++, 就必须得考虑的非常周全了
总的来说,技巧方面,我们使用了多个布尔变量来指明当前的状态。
步骤方面,首先' '肯定是要跳过的,
class Solution {
public:
bool isNumber(string s) {
//num用来标志是否是数字, numAfterE用来指代的是e后面的数字是不是数字
//dot用来看有没有点存在,exp用来看有没有指数,sign用来看有没有正负号
bool num = false, numAfterE = true, dot = false, exp = false, sign = false;
int n = s.size();
//遍历字符串
for (int i = 0; i < n; ++i) {
//如果是空格
if (s[i] == ' ') {
//如果在我们确定它的状态后出现空格并且它的后一项又不是空格,那就一定错误
if (i < n - 1 && s[i + 1] != ' ' && (num || dot || exp || sign)) return false;
}
//如果出现加号或减号
else if (s[i] == '+' || s[i] == '-') {
//如果不是在第一位,并且前面不是e,并且前面不是空的,则说明是错误的
if (i > 0 && s[i - 1] != 'e' && s[i - 1] != ' ') return false;
//当前数字是有符号存在的
sign = true;
}
//碰到了数字
else if (s[i] >= '0' && s[i] <= '9') {
//把数字存在设为true
num = true;
numAfterE = true;
}
//遇到'.'
else if (s[i] == '.') {
//已经有点存在或者有e存在,即在这个点之前出现过了,(看来是不允许1e-2.7这种数的)
if (dot || exp) return false;
dot = true;
}
else if (s[i] == 'e') {
if (exp || !num) return false;//如果前面出现过e或者前面没出现过num。
exp = true;
//看到第一个e,先把numAfterE设为false,然后看能不能找到数字让numAfterE变为true
numAfterE = false;
} else return false;
}
//必须要e前面的数字和e后面的数字都正确
return num && numAfterE;
}
};
具体判断原则:
首先,从题目中给的一些例子可以分析出来,我们所需要关注的除了数字以外的特殊字符有空格 ‘ ’, 小数点 '.', 自然数 'e/E', 还要加上正负号 '+/-", 除了这些字符需要考虑意外,出现了任何其他的字符,可以马上判定不是数字。下面我们来一一分析这些出现了也可能是数字的特殊字符:
1. 空格 ‘ ’
空格分为两种情况需要考虑,一种是出现在开头和末尾的空格,一种是出现在中间的字符。出现在开头和末尾的空格不影响数字,而一旦中间出现了空格,则立马不是数字。
解决方法:预处理时去掉字符的首位空格,中间再检测到空格,则判定不是数字。
2. 小数点 '.'
小数点需要分的情况较多,首先的是小数点只能出现一次,但是小数点可以出现在任何位置,开头(".3"), 中间("1.e2"), 以及结尾("1." ), 而且需要注意的是,小数点不能出现在自然数 'e/E' 之后,如 "1e.1" false, "1e1.1" false。还有,当小数点位于末尾时,前面必须是数字,如 "1." true," -." false。
解决方法:开头中间结尾三个位置分情况讨论。
3. 自然数 'e/E'
自然数的前后必须有数字,即自然数不能出现在开头和结尾,如 "e" false, ".e1" false, "3.e" false, "3.e1" true。而且小数点只能出现在自然数之前,还有就是自然数前面不能是符号,如 "+e1" false, "1+e" false。
解决方法:开头中间结尾三个位置分情况讨论。
4. 正负号 '+/-"
正负号可以在开头出现,可以在自然数e之后出现,但不能是最后一个字符,后面得有数字,如 "+1.e+5" true。
解决方法:开头中间结尾三个位置分情况讨论。
下面我们开始正式以开头、中间、结尾三个不同位置来分情况进行讨论:
1. 在讨论开头、中间、结尾三个不同位置之前做预处理,去掉字符串首尾的空格,可以采用两个指针分别指向开头和结尾,遇到空格则跳过,分别指向开头结尾非空格的字符。
2. 对首字符进行处理,首字符只能为数字或者正负号 '+/-",我们需要定义三个flag以标志我们之前检是否测到过小数点,自然数和正负号。首字符如为数字或正负号,则标记对应的flag,若不是,直接返回false。
3. 对中间字符的处理,中间字符会出现五种情况,数字,小数点,自然数,正负号和其他字符。
若是数字,标记flag并通过。
若是自然数,则必须是第一次出现自然数,并且前一个字符不能是正负号,而且之前一定要出现过数字,才能标记flag通过。
若是正负号,则之前的字符必须是自然数e,才能标记flag通过。
若是小数点,则必须是第一次出现小数点并且自然数没有出现过,才能标记flag通过。
若是其他,返回false。
4. 对尾字符处理,最后一个字符只能是数字或小数点,其他字符都返回false。
若是数字,返回true。
若是小数点,则必须是第一次出现小数点并且自然数没有出现过,还有前面必须是数字,才能返回true
以下是一些例子,可以通过这些例子了解leetcode对有效数字的判断标准:
string s1 = "0"; // True
string s2 = " 0.1 "; // True
string s3 = "abc"; // False
string s4 = "1 a"; // False
string s5 = "2e10"; // True
string s6 = "-e10"; // False
string s7 = " 2e-9 "; // True
string s8 = "+e1"; // False
string s9 = "1+e"; // False
string s10 = " "; // False
string s11 = "e9"; // False
string s12 = "4e+"; // False
string s13 = " -."; // False
string s14 = "+.8"; // True
string s15 = " 005047e+6"; // True
string s16 = ".e1"; // False
string s17 = "3.e"; // False
string s18 = "3.e1"; // True
string s19 = "+1.e+5"; // True
string s20 = " -54.53061"; // True
string s21 = ". 1"; // False
总结:对于多情况讨论的题目,要敢于去试验,并且可以通过设置状态参量(布尔型)来解决判断。