题目: 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、“5e2”、"-123"、“3.1416”、“0123"都表示数值,但"12e”、“1a3.14”、“1.2.3”、“±5”、"-1E-16"及"12e+5.4"都不是。
示例:
输入:+100
输出: true
思想: 这个题最简单的做法就是遍历字符串,判断字符串是否符合标准,但是这个好麻烦😭,特别是测试用例,好多奇怪的测试用例。
那我们根据上述例子可以将符合标准的字符串分为两类规格:
- 整数:A . B e/E C,其中A必须在【+,-,0~9】取值,B为小数点后面的值,所以必须为【0~9】,C指数可以包含+,-,所以必须为【+,-,0~9】
- 小数:B. e/E C,A可以不存在即【.23】B,C和上面取值范围一样。
那我们可以写出两个函数,一个判断是否在【+,-,0~9】,一个判断是否在【0~9】范围内。
- 我们定义isnum(string &s,int &i) 函数来判断字符串从i位置开始是否在[0~9]之间。
- 参数使用引用的目的是为了让 i 的值真正的改变,最开始我没写&, i 的值只在这个函数体里变化,跳出函数后 i 的值没有任何无变化,这就是需要传地址进去才可以,所以用&。
- 我们从字符串的str[i]开始循环判断,如果str[i]属于0~9,那么i++,继续判断,直到到达结尾或者不属于,我们return true;
- 最开始我们用temp保存 i 的初始值,那么如果 i <=temp,就表示 i 没有进入循环,即str[i]不在【0~9】范围内,return false;
- 定义isstart(string &s,int &i) 函数判断字符串从 i 位置开始是否在【+,-,0~9】之间,我们先判断是否和+,-相等,相等就i++,然后调用判断数字的函数isnum即可。
这个就是我们需要实现的函数,我们下面就遍历字符串,然后调用:
- 力扣上的测试用例有的包含空格,前面或者后面存在空格,结果是正确的,所以我们需要处理空格,在开始时,如果str[i]==’ ',那么我们就 i ++,跳过空格。
- 定义bool类型的flag来保存结果。
- 第一次判断小数点之前的数: 判断A,即小数点之前的数值是否符合标准,那么直接调用flag=isstart()即可。
- 第二次判断小数点之后的数: 如果str[i]==‘.’ ,表示存在小数,那么小数点后的数值必须全为0~9,那么调用函数isnum();注意: 因为【.3】和【1.】也符合标准,所以第一次判断小数点之前的值不存在或者第二次判断小数点之后的数不存在也是正确的,故总结出来,只要第一次判断和第二次判断一个存在即可,所以有:flag=flag || isnum() 只要第一次第二次判断一个正确即可。
- 第三次判断指数: 如果str[i]==‘e’ || str[i] ==‘E’,表示存在指数,因为指数存在正负,所以调用isstart(),必须前两次判断结果为true,这次也为true,结果才为true,所以为:flag=flag && isnum()
- 最后处理后面的空格,碰到i++即可。
- 最后判断 i 是否到达结尾并且flag是否为true,成立则字符串符合标准,否则不符合。
我们需要明确几个点:
- 主函数调用时,不需要循环整个字符串,因为我们在两个判断函数中已经遍历字符串,i++在移动,所以主函数只需要判断出现了哪种情况即可。
- flag每一次判断的值,不是覆盖上一次的,因为是判读整个字符串,所以必须每一个部分都需要符合规则才可以,所以这一次判断的flag和上一次的存在【||】或者【&&】的关系。
那我们给出代码:
bool isnum(string &s,int &i)
{
int temp=i;//用来判断i是否判断成功
while(i<s.size() && s[i]>='0' && s[i]<='9')
{
i++;
}
if(i>temp)//表示s[i]符合要求,或者小数点后无数据也正确
{
return true;
}
return false;
}
//判断整数部分是否为+-0~9,
bool isstart(string &s,int &i)
{
if(i<s.size() && s[i]=='+' || s[i]=='-')//碰到+-跳过即可
i++;
return isnum(s,i);//判断数字即可
}
bool isNumber(string s)
{
if(s.empty())
return false;
int i=0;
//开头不能有空格
while(s[i]==' ') ++i;
//判断开头整数,是否为+,-,0~9
bool flag=isstart(s,i);
//判断是否出现小数点,表示小数来了,判断小数点后面的数据是否为数字
if(i<s.size() && s[i]=='.')
{
i++;//跳过小数点
flag= isnum(s,i) || flag;//这个不用&&,因为可以不存在整数,直接小数点,调用判断数字函数
}
//存在指数,后面数据必须全为数字
if(s[i]=='e'||s[i]=='E')
{
i++;
//指数后面可以跟+-符号,所以调用可以判断符号和数字的
flag=flag && isstart(s,i);//一定要&&得到结果
}
//去除结尾空格
while(s[i]==' ')
i++;
if(!flag || i!=s.size())
{
return false;
}
return true;
}
int main()
{
string s;
cin>>s;
cout<<isNumber(s);
}
这个题目力扣的测试用例比较特殊,所以需要考虑到很多特殊情况,所以需要多次提交探索,还有一种是永动机处理解决,从编译原理角度处理,博主不才,放弃了。
加油哦!💪。