当前位置:首页 > 公众号精选 > 码农的荒岛求生

这是LeetCode中的第8号题目,String to Integer (atoi),也就是字符串转数字,我们常用的库函数atoi就是用来进行该转换的,有意思的是这个题目点赞的只有1000+,不喜欢的有7000+:

实际上从题目的通过率就可以看出来,这个题目的通过率只有百分之十几,很显然是大家提交了N多次都不通过才点的不喜欢吧。

为什么这个题目的通过率这么低呢?是这个题目很难吗?不是的,题目很简单,实现起来也没有什么技巧可言,这个题目难在需要考虑的点很多,题目要求:

  1. 给定的字符串开头可能有很多空白字符,因此需要在真正将字符转为数字之前需要首先过滤掉空白字符

  2. 给定的字符串可能包含有 "+" 或者 "-" ,用来表示这是正数还是负数

  3. 如果第一个非空白字符既不是"+"、"-",也不是数字,那么返回0

  4. 在将字符转为数字的过程中,如果遇到非数字字符则停止转换

  5. 如果转换后的数字大于int能表示的最大数,则直接返回INT_MAX (2^31 − 1)

  6. 如果转换后的数字小于int能表示的最小数,则直接返回INT_MIN (−2^31)

那么我们该怎么解决这个问题呢?

实现思路

由于这个问题的解决非常直观,就是把字符串转为数字,因此只需要实现细节,接下来我们就以字符串“     -6082”为例来讲解,该字符串我们记为变量str,并用变量i记录我们已经遍历到哪个位置了,我们使用"_"来表示空表字符,如图所示:

首先我们需要过滤掉字符串开头中可能存在的空白字符,因此我们需要判断当前字符是不是空白符:

int i=0;while(i' ')++i;

当这段代码执行完毕后,我们来到了第一个非空表字符,如图所示:

此时我们需要判断以下几件事:

  • A,第一个非空字符是不是"+",如果是,则说明这是个正数

  • B,第一个非空字符是不是"-",如果是,则说明这是个负数

  • C,第一个非空字符是不是数字,如果不是则直接返回

因此,我们需要定义一个变量sign,用来表示该数字是正数还是负数:

 int sign = 1;    if (str[i] == '+')  // A    ++i;    else if (str[i] == '-'){  // B    ++i;    sign = -1;    } else if (!('0'<=str[i] && str[i]<='9')) {  // C    return 0;    }

由于当前字符是"-",因此变量sign为-1。这样我们来到了第一个既不是空白字符也不是正负号的字符,如果这个位置是数字,那么我们就要开始将字符转为数字了,为此我们需要定义变量long int r=0,用于记录转换后的数字,如图所示:

之所以定义为long int是因为需要判断当前数字是不是已经超出了int能表示的最大范围,那么该如何依次将字符转为数字呢?使用以下代码:

r = r * 10 + 当前字符所代表的数字

接下来你就明白这句代码的意思了,由于当前数字是6,因此:

r = 0 * 10 + 6

如图所示:

现在你应该能明白接下来几个数字是怎么计算了吧:

在计算r的过程中我们还要不断判断r是否已经超过了int能表示的最大范围,如果超过了那么停止转换并直接返回int能表示的最大数,并且如果当前字符不是数字的话也直接返回r,这个过程用代码表示就是:

long int r=0;while(iif ('0'<=str[i] && str[i]<='9') {r=r*10+str[i]-'0';} else {return r*sign;}if (r*sign > (int)0x7fffffff)return 0x7fffffff;if (r*sign < (int)0x80000000)return 0x80000000;++i;}

现在你应该明白这整个过程了吧。

代码实现

上述分析过程的完整代码实现是:

int atoi(string str) {    int len = str.length();    if (len == 0)        return 0;    int i=0;    // 过滤掉空格    while(i<len && str[i] == ' ')        ++i;        if (i == len)        return 0;    int sign = 1;    if (str[i] == '+')        ++i;    else if (str[i] == '-'){        ++i;        sign = -1;    } else if (!('0'<=str[i] && str[i]<='9')) {        return 0;    }
    long int r=0; while(i<len){ if ('0'<=str[i] && str[i]<='9') { r=r*10+str[i]-'0'; } else { return r*sign; } if (r*sign > (int)0x7fffffff) return 0x7fffffff; if (r*sign < (int)0x80000000) return 0x80000000; ++i; } return r*sign;}

总结

这个题目本身思路并不难,但是难在对细节的处理,代码中要判断各种情况,当你下次再使用各种库函数的时候(比如atoi())是不是应该感谢一下库的作者帮我们处理这这么多琐碎的事情,而实际上软件工程也正是基于这样的逻辑建立起来的,那就是“站在巨人的肩膀之上”。

现在,使用任何语言写一个最简单的程序,哪怕只是一个空的main函数,这样一个最简单程序的运行背后是无数编程大牛努力的结果,这背后是操作系统、编译器、解释器、编程语言标准库,正是这些基石使得现在的程序员可以只关注解决自己特定的问题,创世的工作已经有人完成,剩下的舞台就交给你了。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭