问题:

剑指 Offer 67. 把字符串转换成整数
难度中等17
写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。

首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−2, 2− 1]。如果数值超过这个范围,请返回 INT_MAX (2− 1) 或 INT_MIN (−2) 。
示例 1:

  1. 输入: "42"
  2. 输出: 42

示例 2:

输入: "   -42"
输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。
     我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。


示例 3:

输入: "4193 with words"
输出: 4193
解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。

示例 4:

输入: "words and 987"
输出: 0
解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
     因此无法执行有效的转换。

示例 5:

输入: "-91283472332"
输出: -2147483648
解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 
     因此返回 INT_MIN (−231) 。

解答:

根据题意,需要注意的四个点:

  1. 首部空格字符:直接删除点,或者跳过
  2. 非数字字符:直接返回 0
  3. 符号位 ‘-‘ or ‘+’:用一个变量记录正负
  4. 数字字符:
    1. 字符转数字:字符 - ‘0’
    2. 数字拼接:从左向右依次遍历,设当前数字字符为 c,结果为 res, 则拼接公式为:

res = res 10 + c - ‘0’;
溢出处理:
整数的最大值:Integer.MAX_VALUE = 2^32 -1 = 2147483648 - 1 = 2147483647 十六进制(0x7fffffff)
最小值:Integer.MIN_VALUE = - 2^32 =* 2147483648 十六进制(0x8ffffffff)

在每轮整数拼接的时候,判断在这轮 res 拼接后的值是否会超过 Integer.MAX_VALUE。
设置一个 res 即将要超过 Integer.MAX_VALUE 的边界,boundary = Integer.MAX_VALUE / 10,下面两中情况会越界:

  1. res > Integer.MAX_VALUE / 10 ,也就是 2147483647 / 10 = 214748364。res 超过这个值,那么下面进行拼接的是 res = res * 10 + (str.charAt(i) - ‘0’) 一定会超过最大值。
  2. res = Integer.MAX_VALUE / 10 && str.charAt(i) > ‘7’ , 当 res = 214748364 并且待拼接的数字超过了 7, 那么在下一轮 res = res*10 + (str.charAt(i) - ‘0’) 一定超过了 214748364。

**

class Solution {
    public int strToInt(String str) {
        char[] cs = str.trim().toCharArray();
        int i = 0, sign = 1;
        int res = 0;
        if(cs.length == 0) return 0;
        char c = cs[i];
        // 判断符号位
        if(c == '-'){
            sign = -1;
            i ++;
        }else if (c == '+'){
            i ++;
        }else if(c < '0' || c > '9'){  // 非数字字符
            return 0;
        }
        for( ; i < cs.length; i ++){
            c = cs[i];
            if(c < '0' || c > '9')
                break;
            int max = Integer.MAX_VALUE/10;
            // 溢出处理
            if(res > max || (res==max && cs[i] > '7')) 
                return sign == 1? Integer.MAX_VALUE : Integer.MIN_VALUE;
            res = res*10 + (c - '0'); 
        }
        return res*sign;
    }
}

大佬的解答:

class Solution {
    public int strToInt(String str) {
        char[] cs = str.trim().toCharArray();
        if(cs.length == 0) return 0;
        int i = 1, sign = 1;  // 假设第一位为符号位:+,-,并且数字为正
        int res = 0;
        if(cs[0] == '-') sign = -1; // 符号位为负
        else if(cs[0] != '+') i = 0;  // 如果第一位不是符号位,是数字字符或者非数字字符
        for( ; i < cs.length; i ++){
            if(cs[i] < '0' || cs[i] > '9') break;
            int max = Integer.MAX_VALUE/10;
            // 溢出判断
            if(res > max || (res==max && cs[i] > '7')) return sign == 1? Integer.MAX_VALUE : Integer.MIN_VALUE;
            res = res*10 + (cs[i] - '0'); 
        }
        // 返回符号位与值的乘积
        return res*sign;
    }
}