当前位置 博文首页 > String to Integer (atoi)_让代码改变世界:LeetCode 8

    String to Integer (atoi)_让代码改变世界:LeetCode 8

    作者:[db:作者] 时间:2021-07-10 18:58

    这几天时间比较宽松,尽量多整理几道吧,希望每个人的努力都能换来想要的生活。。。

    这是leetcode第八题,说实在的,本人感觉是出的不如前面几道,这道题怎么说呢,很平常,但一些特殊情况考虑的很多很杂散,不像是在做算法,倒像是在玩儿“找茬儿”,我着重说点有用的吧,原题如下:

    Implement?atoi?to convert a string to an integer.

    Hint:?Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.

    Notes:?It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.

    题目的要求可以用一句话说明白:把字符串转化为整数。

    这个想对于一点儿编程基础的人都不会有什么问题,而题目中的Notes也说了,这个题目主要是考察你对“各种”输入的考虑是否周全。字符串转数字大家时并不是都能转化的,这一点大家都能理解。比如说字符串中有不是数字的字符,再进一步可能会考虑的有负数,再再进一步可能会考虑到转化溢出的情况。个人认为能考虑到这些基本就可以了,不过通过编程发现其实要通过验证还要处理很多“变态输入”。比如,字符串中有空格,这种情况本来就应该是每个情况都有自己处理方式的,但题目中并没有这样的具体要求,通过实验发现题目是要求把前面的空格忽略,然后中间的空格当做一般的非数字字符处理。而对于非数字字符的处理也挺奇怪,遇到非数字字符时转化停止,只算前面的数字就可以了,总之这种情况很多,其实只要要求明确了,这些并不算难,但题目中没有要求,要通过实验得到,好像评判标准也是凑出来的,好了不吐槽了,上代码吧。

    class Solution {
    public:
        int myAtoi(string str) {
    		//滤除空格
    		string str1;
    		string::iterator it=str.begin();
    		for(;*it==' ';++it);
    		for(string::iterator it2=it;it2!=str.end();++it2)
    		{
    			str1.push_back(*it2);
    		}
    
    		str=str1;
    		//确定是否有正负号
    		bool neg=false;
    		if(str[0]=='-')//前面有负号
    			neg=true;
    		bool pos=false;
    		if(str[0]=='+')//前面有正号
    			pos=true;
    		int len=str.size();
    		int result=0;
    		for(int i=(neg||pos)?1:0;i<len;++i)
    		{
    			if(str[i]<'0'||str[i]>'9')//不是数字,返回
    				return neg?(-1*result):result;
    			if(result > INT_MAX/10)return neg?INT_MIN:INT_MAX;
    			result *= 10;
    			if(result > INT_MAX-str[i]+'0')return neg?INT_MIN:INT_MAX;
    			result += str[i]-'0';
    		}
              return neg?(-1*result):result;
        }
    };
    里面的各种“补丁”语句大家没必要纠结,大体思路明白就好了,注意并学会这几点就好:

    (1)“-”和“+”。一般人可能会想到符号而忘了正号,这种“灯下黑”的错误还是要注意一下的。

    (2)不是数字的情况。这个大家一定要考虑到,这是转化数字最基本的要求嘛。

    (3)溢出判断。这一点要在这里着重说一下,并为上一题(第七题)的错误作出改正。

    溢出判断也是数字转化过程中要注意的很重要的一点,严谨的说,每一次算术都有溢出的可能,所以每次运算都应该进行溢出判断。当然实际编程过程中溢出毕竟只是少数情况,所以一般是不需要进行判断的,但这种转化的题目就必须要考虑了,因为这不是一个实际中的有意义的数值,而是通过机械式的转化得到的一种形式或者成为符号。

    那该怎么进行溢出判断呢?是在运算前,还是运算后?是利用符号改变还是大小改变?这些情况很多,我们先来看一下溢出的本质:

    我们知道(我假设你知道,不知道的话可以查看相关资料)数字在机器中,也可以说在电脑中,是用补码表示的,那数字的补码是怎么表示的呢,又是怎么溢出的呢,我们不去讨论里面的各种原理,只是来看一些实例:假设某种型的存储空间为4为二进制编码,我们知道,它一共可以表示2^4=16种不同的数字,我们就让它来表示-8—7这16个数字。-8—7的原码、反码和补码列于下表:



    从这个图中可以看到,-0和+0的原码是不同的,但补码是相同的,所以“多出来“的位置正好给了-8,而没有+8。另外通过补码一列我们可以总结出这样的规律:补码从0000到1111,对应的数字为从0到7然后突变成-8然后到-1。而这里的突变点,就是我们所说的溢出点,也就是说7再加1就溢出了(本来应该是8,变成-8了),而-8再减1也会溢出(本来应该是-9变成7了)。从突变点看貌似可以通过符号的改变判断是否溢出,但仔细思考一下会发现,这只是”小的“溢出,如果7再加16呢?它还是7!所以这种方法是不对的。我们在上一题中提到了用”还原法“,当时并没有出现错误且通过了验证,但通过今天的分析我们知道,其实上次的成功只是侥幸罢了。能还原的并不一定没有溢出,当然不能还原的是一定溢出了,这个例子就不用再举了吧。那么话说回来,我们该怎么判断溢出呢?

    通过分析可知,溢出是一个很随意的过程,溢出的结果也是很难捉摸。所以我们应该把溢出扼杀在摇篮里,也就是说要把”溢出后判断“的思维改为”判断要溢出“。说直白点儿,就是在运算前判断是否会溢出,有了这个思路就容易入手了,具体的语句已经写在程序里了。如果你还是会写成if(result*10>INT_MAX),那证明,怎么说呢,你要走的路还很长啊,加油吧。

    明天是抗战70周年的纪念日,在此向我们的革命先烈致以敬意,也希望每个人都能珍惜来之不易的和平,珍惜来之不易的幸福生活。

    cs
    下一篇:没有了