字符串转换成整数:输入一个表示整数的字符串,把该字符串转换成整数并输出,例如输入字符串”345”,则输出整数345。

在笔试面试中,atoi 即「字符串转换成整数」是一个经典问题了,此题无关算法,考察的更多是编码能力和细节考虑能力。因此自己就动手写了下,写完之后,打开 JDK 的源码想看看大牛是怎么写的,所谓「站在巨人的肩膀上」,果然还是有很多有意思的东西的。

首先,实现的思路是扫描整个字符串,扫描到当前字符时,将之前的结果乘以10加上当前字符代表的数字。

思路是很简单,但是有很多细节需要考虑,也是本题考查的重点。

开头可能会有 ‘+’ 和 ‘-‘,表示整数的正负。

字符串为 null 或是空(””)呢?

字符串中包含非数字的字符

只有一个 “+” 或 “-“ 字符呢?

最后就是溢出问题。

先放出我的代码吧!public static int atoi(String s) throws Exception{

if (s == null || s.length() == 0) {

throw new Exception("illegal number input");

}

final int MAX_DIV = Integer.MAX_VALUE / 10;

final int MIN_DIV = -(Integer.MIN_VALUE / 10);

final int MAX_M = Integer.MAX_VALUE % 10;

final int MIN_M = - (Integer.MIN_VALUE % 10);

int result = 0;

int i = 0, len = s.length();

int sign = 1;

int digit = s.charAt(0); //当前字符

if (digit == '-' || digit == '+') {

if (digit == '-') {

sign = -1;

}

if (len == 1) {

throw new Exception("illegal number input");

}

i++;

}

while (i < len) {

digit = s.charAt(i++) - '0';

if (digit >= 0 && digit <= 9) {

if (sign > 0 && (result > MAX_DIV || (result == MAX_DIV && digit > MAX_M))) { // 正数溢出

throw new Exception("number overflow");

} else if (sign < 0 && (result > MIN_DIV || (result == MIN_DIV && digit > MIN_M))) { //负数溢出

throw new Exception("number overflow");

}

result = result * 10 + digit;

} else {

throw new Exception("illegal number input");

}

}

return sign > 0 ? result : -result;

}

上述代码中对于一些非法输入都做了异常处理,主要需要看的地方是溢出的判断。

一般判断溢出会这样判断 digit > INT_MAX - result*10 (先不考虑正负问题),但是这段代码是有问题的。

我们知道INT_MAX = 2147483647, 如果输入的字符串是2147483657,那么执行到最后一位时,会有 result*10 = 2147483650 > INT_MAX,此时已经溢出,所以答案必然出错。

在July的博客中提到比较好的解决方法是用除法和取模。

先用 result 与 INT_MAX /10 进行比较: 若 result > INT_MAX/10(当然同时还要考虑 result=INT_MAX/10 的情况), 说明最终得到的整数一定会溢出, 故此时可以当即进行溢出处理,从而也就免去了计算 result*10 这一步骤。

当 result=INT_MAX/10 时,若 digit > INT_MAX%10,说明 result*10+digit 最终还是会溢出,也直接当溢出处理。

比如,对于正数来说,溢出有两种可能:

一种是诸如 2147483650,即 result > MAX/10 的;

一种是诸如 2147483649,即 result == MAX/10 && digit > MAX%10 的。

由于INT_MAX = 2147483647 而 INT_MIN = -2147483648,两者绝对值不相等。因此,正负数溢出的条件不一样,代码中用了两个条件来判断溢出情况。

再来学习下 JDK 中 parseInt 的实现吧!

/*

* Integer 类中的 parseInt 函数

* Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.

*/

public static int parseInt (String s) throws NumberFormatException{

return parseInt(s,10);

}

public static int parseInt(String s, int radix)

throws NumberFormatException

{

/*

* WARNING: This method may be invoked early during VM initialization

* before IntegerCache is initialized. Care must be taken to not use

* the valueOf method.

*/

if (s == null) {

throw new NumberFormatException( "null"); //判断null的情况

}

if (radix < Character. MIN_RADIX) { //转换的进制不能小于2

throw new NumberFormatException( "radix " + radix +

" less than Character.MIN_RADIX");

}

if (radix > Character. MAX_RADIX) { //转换的进制不能大于36

throw new NumberFormatException( "radix " + radix +

" greater than Character.MAX_RADIX");

}

int result = 0; //对应整数结果

boolean negative = false; //保存整数的正负状态

int i = 0, len = s.length();

int limit = -Integer. MAX_VALUE; //合法数字的上限(下限)

int multmin; //在做乘法计算时能走到的合法上限(下限)

int digit; //当前字符对应的数字

if (len > 0) {

char firstChar = s.charAt(0);

if (firstChar < '0') { // Possible leading "+" or "-"

if (firstChar == '-') {

negative = true;

limit = Integer. MIN_VALUE;

} else if (firstChar != '+')

throw NumberFormatException. forInputString(s);

if (len == 1) //不能只有一个"+"或者"-"

throw NumberFormatException. forInputString(s);

i++;

}

multmin = limit / radix;

while (i < len) {

// Accumulating negatively avoids surprises near MAX_VALUE

digit = Character. digit(s.charAt(i++),radix); //以指定的进制转换整数字符

if (digit < 0) { //不能是非数字

throw NumberFormatException. forInputString(s);

}

if (result < multmin) { //判断溢出

throw NumberFormatException. forInputString(s);

}

result *= radix;

if (result < limit + digit) {

throw NumberFormatException. forInputString(s);

}

result -= digit;

}

} else { //字符串不能为"",即长度要大于0

throw NumberFormatException. forInputString(s);

}

return negative ? result : -result;

}

可以看到parseInt(String s)函数调用了parseInt(String s, int radix),源码中参数的检查,异常输入的判断都非常全面。可以说严谨和巧妙是这段程序最大的特点。比较难懂的可能是溢出判断那一段。

if (result < multmin) { //判断溢出

throw NumberFormatException. forInputString(s);

}

result *= radix;

if (result < limit + digit) {

throw NumberFormatException. forInputString(s);

}

result -= digit;

其实与上文的溢出判断思想是差不多的, 只不过可以发现 JDK 将所有的整数先当做负数来处理了,这有什么妙处呢?

我们知道有符号 int 的上下限是-2147483648 ~ 2147483647,可见负数表达的范围比正数多一个,这样就好理解为什么在开头要把 limit 全部表达为负数(下限)。这样的操作减少了后续的判断,可以一步到位,相当于二者选择取其大一样,大的包含了小的,不用像我的代码一样正负数情况都判断一次。同理,那么 multmin 也都是负数了,而且可以认为是只和进制参数 radix 有关系。在这里 multmin 就是-INT_MAX/10,当负数时就是INT_MIN/10。所以与上文类似,第一个条件就是若-result < -INT_MAX/10则是溢出。不满足第一个条件的情况下,result*10肯定不会溢出了。所以第二个条件判断若 - result*10 < -INT_MAX + digit,则是溢出。

比如对于最大的负数来说,当扫描到最后一位时,result = -214748364,multmin=-214748364

第一个条件result < multmin不满足, 执行result *= radix之后,result = -2147483640

第二个条件result < limit + digit,即 -2147483640

所以正常输出。

oracle 转化为整数,字符串转换成整数——从源码学习相关推荐

  1. python 字符串转换成整数

    | String to Int 写一个函数 StrToInt,实现把字符串转换成整数这个功能.不能使用 atoi 或者其他类似的库函数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个 ...

  2. 【Java】 剑指offer(67) 把字符串转换成整数

      本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 请你写一个函数StrToInt,实现把字符串转换成整数这个功能 ...

  3. 剑指offer——面试题49:把字符串转换成整数

    剑指offer--面试题49:把字符串转换成整数 Solution1: 代码写的啰嗦,但思路清晰..LeetCode上有相似的题目并考虑了溢出,可以参考LeetCode8答案 class Soluti ...

  4. 把字符串转换成整数 一点小小的经验总结

    把字符串转换成整数 功能:实现把字符串转换成整数这个功能.不能使用 atoi 或者其他类似的库函数 题解分析 会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止 eg:"  ...

  5. Leetcode错题本1-实现一个 atoi 函数,使其能将字符串转换成整数。

    题目描述 请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止.接下来的转化规则如下: 如果第一个非空字符为正或者 ...

  6. 字符串转换成整数(3种方法)

    请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止.接下来的转化规则如下: 如果第一个非空字符为正或者负号时,则 ...

  7. 将十六进制的字符串转换成整数

    #include "stdafx.h" #include<stdio.h> #include<string.h>/*将大写字母转换成小写字母*/ int t ...

  8. 程序员面试题精选100题(17)-把字符串转换成整数[算法]

    题目:输入一个表示整数的字符串,把该字符串转换成整数并输出.例如输入字符串"345",则输出整数345. 分析:这道题尽管不是很难,学过C/C++语言一般都能实现基本功能,但不同程 ...

  9. 判断字符为空_49. 把字符串转换成整数(剑指offer)

    49. 把字符串转换成整数 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数. 数值为0或者字符串不是一个合法的数值则返回0. 输入描述: 输入一个字符串,包括数字字母符号,可以为空 输 ...

最新文章

  1. 使用React.js开发自己的Chrome插件
  2. java 039 s rule_Java开发架构篇:DDD模型领域层决策规则树服务设计
  3. 设计模式--简单工厂模式
  4. [javaweb] servlet的生命周期 (二)
  5. 由于更换了java版本,Eclipse启动时报错:JRE or JDK must be available in order to run Eclipse
  6. 鸿蒙系统安兔兔排行榜,安兔兔评测鸿蒙版下载-安兔兔评测 鸿蒙版v9.0.7-PC6鸿蒙网...
  7. python简单语法_python的基本语法(一)
  8. django-模型类字段选项
  9. 百练 03 复杂的整数划分问题
  10. 支付宝开放生活频道 消费者可直达商家生活号、小程序
  11. H3C OSPF 单区域、多区域(虚连接)配置
  12. 《深度学习Python实践》第20章——回归项目实例
  13. Linux 之shell脚本编程
  14. Matlab 取整函数
  15. 神泣单机服务器维护,神泣单机版
  16. Linux知识点总结(思维导图,建议收藏)
  17. 输入身份证判断性别python最后一位是英文怎么写_身份证号码最后一位,是表示性别用的吗?...
  18. Uva207 PGA Tour Prize Money
  19. 实际业务中的数据分析流程和痛点
  20. mapbox 接入高德矢量地图实战

热门文章

  1. #HTTP协议学习# (二)基本认证
  2. CoordinatorLayout 之深入理解
  3. CSS3 稳固而知新: 居中
  4. Spring中ThreadPoolTaskExecutor的线程调度及问题
  5. 11、查看及测试网络、配置网络地址、内核及模块管理
  6. Open Sans字体兼容问题解决办法[font-face]
  7. 进程内存分配和/proc/xxx/maps简单分析
  8. mysql的root用户添加密码
  9. 监控告警满飞天,Netflix 运维如何做到在家睡到自然醒...
  10. 技术扫盲:关于低代码编程的可持续性交付设计和分析