锻练编程思维——每日一题:《剑指offer》表示数值的字符串

昨天光tm做实验了,写了一堆实验报告,今天上午也是。
所以昨天没写oj题。没写就没写吧(那我不能穿越回昨天233),今天得写了,还是尽量一天一道,循序渐进

题目描述

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。
题目给的代码框架:

class Solution {
public:
    bool isNumeric(char* string)
    {
        
    }

};

题目分析

  • 首先你找出表示数值的字符串似乎很难找,太多了。

  • 那就找出不表示数值的字符串呗,用**排除法**

  • 怎么排除呢,统计字符串的字符表示什么及其位置呗。对吧,以我的水平只有这种方法行得通。你看上面的题干提供的参考字符串,里面有一些字符的位置是不符合表示数值的字符串的字符位置的有一些字符不是表示数值的字符

  • 所以,我根据题目给的表示or不表示数值的参考字符串,列出以下排除不表示字符串的依据 :(统计’+’ ‘-’ ‘e’ ‘E’ ‘.’ 五个字符出现的次数和位置并筛出一部分明显不表示数值的字符串

    • 1.字符串的字符不是E/e,小数点,0~9,+/-的,则该字符串不表示数值
    • 2.字符串是空串,则该字符串不表示数值
    • 3.字符串的字符E/e,小数点出现两次以上,则该字符串不表示数值
    • 4.字符串的字符+/-未放在紧接E/e(如果有E/e字符)之后或字符串首位,也就是说除了这两个位置可以有+/-字符其他位置如果还有+/-字符的字符串则不表示数值
    • 5.小数点放在E/e(如果有E/e字符)之后了,则该字符串不表示数值
    • 6.E/e字符之后没有其他字符,则该字符串不表示数值
  • 统计’+’ ‘-’ ‘e’ ‘E’ ‘.’ 五个字符出现的次数和第四种情况结合一下,可以有效筛选命中第四种情况的非数值字符串

    • E/e(如果有E/e字符)后紧接+/-字符,+/-字符出现次数自减1
    • +/-字符出现在字符串首位,+/-字符出现次数自减1
    • 然后如果+/-字符出现次数还不为0,即命中除了这两个位置可以有+/-字符其他位置如果还有+/-字符的字符串的情况,此时该字符串不表示数值,return false
  • 结合上面的思路和规则,我们可以编写代码了。(注意先进行异常处理,也就是空串不用判断是否表示数值,肯定不表示,直接返回false即可。)

  • 表示数值的字符串返回true,经过下面的5轮筛选的字符串还未出局(未被排除)后才能返回true

  • 被筛选后需要排除的字符串,命中哪个排除情况,就在哪个排除情况对应的if语句里写return false;

  • 统计次数和位置用for循环遍历字符串即可,因为我要统计的字符位置除+/-字符外都是一锤定音。+/-字符记录次数即可,位置不必记录,也用不到。

  • 判断字符串是否需要排除的情况用if语句,关于E/e字符后的字符情况用if+for循环解决

题解代码

class Solution {
public:
    bool isNumeric(char* string)
    {//排除法
        //unsigned int n=string.size();//不能这么写
        //线上编译器报错:error: member reference base type 'char *' is not a structure or union
        //要写int n=strlen(string);
        int n=strlen(string);
        if(n==0)
        {
            return false;//空串,返回否(不表示数值,下同)
        }
        int cntdat=0,cnteE=0,cntplusminer=0,posdat=0,poseE=0;
        //int posplusminer=0;用不到+/-字符的位置。
        //error: use of undeclared identifier 'posdat',出现该错误原因:posdat前面是;
        //改成英文格式的,
        //开始统计'+''-''e''E''.'五个字符出现的数和位置并筛出一部分明显不表示数值的字符串
        for(int i=0;i<n;i++)
        {
            if(string[i]!='e'&&string[i]!='E'&&!(string[i]>='0'&&string[i]<='9')
               &&string[i]!='.'&&string[i]!='+'&&string[i]!='-')
            {
                return false;//出现了除以上字符外的字符均代表该字符串不表示数值,返回false
            }
            //第一轮筛选完毕。开始统计'+''-''e''E''.'五个字符出现的数和位置
            if(string[i]=='.')
            {
                cntdat++;
                posdat=i;
            }
            if(string[i]=='e'||string[i]=='E')
            {
                cnteE++;
                poseE=i;
                
            }
            if(string[i]=='+'||string[i]=='-')//+500样例没过,因为||写成了&&
            {
                cntplusminer++;
                //posplusminer=i;用不到+/-字符的位置。
            }
            
        }
        //第二轮筛选,E/e和.出现两次及以上,+和-共出现三次及以上的字符串不是表示数值
        if(cntdat>=2||cnteE>=2||cntplusminer>=3)
        {
            return false;
        }
        //第三轮筛选,.放在了E/e(如果有E/e)之后的字符串不是表示数值
        if(cnteE&&posdat>poseE)
        {
            return false;
        }
        //第四轮筛选,+/-除放在首位或者紧接E/e(如果有E/e)之后还有其他字符有+/-的(
        //体现在cntplusminer在减掉属于这些除。。的情况的统计字符后还不为0)字符串不是表示数值
        if(string[0]=='+'||string[0]=='-')
        {
            cntplusminer--;
        }
        if(cnteE&&(string[poseE+1]=='+'||string[poseE+1]=='-'))//如果E/e有的话才开始后面的判断
        {
            cntplusminer--;
        }
        if(cntplusminer)//cntplusminer在减掉属于这些除。。的情况的统计字符后还不为0
        {
            return false;
        }
        //第五轮筛选,E/e(如果有的话)后必须为+/-(必须紧跟在E/e后)或者连续一堆数字,否则该字符串
        //不表示数值
        if(cnteE)
        {
            if(poseE==n-1)
            {
                return false;//比如12e这种情况下没有必要再进行筛选了,这个肯定不是字符串表示数值了
            }
            //排除了这种情况后进行第五轮第二次筛选
            int i=poseE+1;
            // error: use of undeclared identifier 'i'
            //原因:i之前在for循环的初始条件那里定义了,仅在for循环里有效,for循环之外无效,
            //这里的i需要重新声明
            if(string[i]=='+'||string[i]=='-')
            {
                i++;
                for(;i<n;i++)
                {
                    if(string[i]<'0'||string[i]>'9')
                    //只要+/-后面有不是0~9的字符,代表该字符串不表示数值
                    {
                        return false;
                    }
                }
            }
        }
        return true;
    }

};

小结

排除法巧妙地运用。虽然暴力,但是简单,对萌新很友好。
所以这个算法还是有待优化的,加油,奥里给!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值