剑指 Offer 67. 把字符串转换成整数

该文讨论了如何编写一个不依赖库函数的StrToInt方法,将字符串转换为整数,重点在于数值边界和非法输入的处理。文中提供了两种解题思路,一种是手动转换和判断,另一种则是错误的使用Integer.parseInt(),并分析了错误原因。
摘要由CSDN通过智能技术生成

题目链接

力扣 剑指 Offer

题目描述

写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。

示例 1:

输入: "42"
输出: 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) 。

解题思路


  由题目和上述示例可以看出,一个正确的数字只有符号位与数字位组成的int型数值,其中符号位为空。这是一个中等难度的题,只需要将每个字符转换成数字加上就行(res = res * 10 + (char - ‘0’))。个人认为难点在于对数值边界和非法输入的判断 。
  数值边界的判定:根据符号位设置一个边界值 Bound(值的大小等于 int 边界值的十分之一),只要此时的 res 小于 Bound ,那么加上这个字符所得的新数必然不可能越界;而 res == Bound 时,判断新加的数和 int 边界值的最后一位就可以了。
  非法输入:null 、字符串长度为0、只有符号位、 不相关字符…

  废话不多说,直接上代码。

// 输入判断
        if (str == null) {
            return 0;
        }

        char[] chars = str.trim().toCharArray();
        if (chars.length == 0){
            return 0;
        }
        int idx = 0;
        int res = 0;
        int sign = 1; // 正负标志
        if (chars[0] == '+') {
            idx++;
        } else if (chars[0] == '-') {
            sign = -1;
            idx++;
        }
        int bound = sign == 1 ? Integer.MAX_VALUE / 10 : Integer.MIN_VALUE / 10;//根据符号位设置边界值
        char currentChar;
        int x;
        for (int i = idx; i < chars.length; i++) {
            currentChar = chars[i];
            if (currentChar < '0' || currentChar > '9') {
                //符号位后只能出现数字
                break;
            }
            x = sign * (currentChar - '0');

            if (sign == 1 && (res > bound || res == bound && x > Integer.MAX_VALUE % 10)) {
                return Integer.MAX_VALUE;
            } else if (sign == -1 && (res < bound || res == bound && x < Integer.MIN_VALUE % 10)) {
                return Integer.MIN_VALUE;
            } else {
                res = res * 10 + x;

            }
        }
        return res;

  可以看到开头先是用了 trim()函数,直接找到第一个非空字符。此时要记得先去除首尾多余空格,再判断长度是否为0,否则会有 “ 若干空格 ” 进入程序中导致,chars【0】直接空指针异常

错题思路

  1. 使用StringBuilder将 ‘+’ | ‘-’ 和 数字拼接起来。
  2. 然后通过Integer.parseInt() 函数直接将拼接好的字符串
if (str == null || str.length() == 0) {
            return 0;
        }
        char[] chars = str.trim().toCharArray();
        StringBuilder sb = new StringBuilder();
        int res = 0;

        int count = 0;  // 数字个数,判断是否越界
        boolean sign = false; // FALSE 为 - ,TRUE 为 +
        boolean appear = false; // 判断数字是否出现过
        if (chars[0] == '-'){
            sb.append(chars[0]);
        }else if (chars[0] == '+') {
            sign = true;
            sb.append(chars[0]);
        } else if (chars[0] > '0' && chars[0] <= '9') {
            count++;
            appear = true;
            sb.append(chars[0]);
        } else {
            // 去除首尾空格后,合法数字的第一位必是 符号位 | 数字位
            return 0;
        }

        for (int i = 1; i < chars.length; i++) {
            if (chars[i] >= '0' && chars[i] <= '9') {
                appear = true;
                count++;
                sb.append(chars[i]);
            } else {
                break;
            }
        }
        if (appear) {
            String tmp = sb.toString();
            Long num = 0L;
            // int 类型的最大值和最小值的十进制位数分别是 10、11
            if (sign && count > 10) {
                return Integer.MAX_VALUE;
            }else if (!sign && count >11){
                return Integer.MIN_VALUE;
            }
            num = Long.parseLong(tmp);
            if (num > Integer.MAX_VALUE){
                return Integer.MAX_VALUE;
            } else if (num < Integer.MIN_VALUE) {
                return Integer.MIN_VALUE;
            }
            res = Integer.parseInt(tmp);
        }
        return res;

   这个思路出错的原因就是没有注意上面说的两点,以为使用了Long就能够避免值溢出;以为排除了空格和英文就没有了其他的非法输入,“00000013456”。
  
  

总结

  主要就是锻炼你思维,如果你思考的时候,能够提前将各种输入字符串可能出现的非法输入,和数据类型的问题发现并分类处理,这题就不难。但是如果不能对把握对数字边界的判断,和字符串输入的种种可能就会走很多的弯路。
   初写博客,如果有更好的解法和建议欢迎留言告诉我。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值