剑指offer面试题67(java版):把字符串转成整数

本文详细解析了如何将字符串转换成整数的问题,提供了一种不使用库函数的方法,并深入探讨了整数溢出的处理策略,适用于面试及日常编程实践。

welcome to my blog

剑指offer面试题67(java版):把字符串转成整数

题目描述

将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。

输入描述:
输入一个字符串,包括数字字母符号,可以为空

输出描述:
如果是合法的数值表达则返回该数字,否则返回0

示例1
输入
+2147483647
1a33
    
输出
2147483647
0
class Solution {
    public int strToInt(String str) {
        str = str.trim();
        if(str.equals("")){
            return 0;
        }
        int n = str.length();
        int p = 0;
        char[] chs = str.toCharArray();
        int res = 0;
        int flag = 1;
        if(chs[p]=='-'){
            flag = -1;
            p++;
        }else if(chs[p]=='+'){
            p++;
        }

        for(; p<n; p++){
            char ch = chs[p];
            if(ch>='0' && ch<='9'){
                //溢出判断
                if(flag==1){
                    //res * 10 + cur > max
                    if(res>(Integer.MAX_VALUE - (ch-'0'))/10){
                        return Integer.MAX_VALUE;
                    }
                }else{
                    //-res * 10 - cur < min
                    if(-res<(Integer.MIN_VALUE + ch - '0')/10){
                        return Integer.MIN_VALUE;
                    }
                }
                res = res*10 + ch - '0';
            }else{
                break;
            }
        }
        return res*flag;

    }
}
第三次做; 这道题真的好! 核心: 1)int越界处理
/*
难点: 字符串形式下考虑越界
int范围[-2147483648, 2147483647]
什么情况下会越界? 复现一下我开始复杂的处理
关于正数
cur == 214748364时, 下一个数字的取值范围只能是[0,7], 其他数字都会导致越界
cur >  214748364时, 如果后面还有数字则会越界

关于负数
cur == -214748364时, 下一个数字的取值范围只能是[0,8], 其他数字都会导致越界
cur <  -214748364时, 如果后面还有数字则会越界

上面的处理不好,下面的写法好!
对于正数
res*10 + cur > max
res > (max-cur)/10时越界

对于负数
-res*10 - cur < min
res > -(min + cur)/10

*/
class Solution {
    public int strToInt(String str) {
        if(str==null || str.length()==0)
            return 0;
        int index=0;
        int n = str.length();
        int res=0;
        char ch;
        //跳过空格; 细节: 对索引进行越界检查
        while(index<n && (ch = str.charAt(index))==' ')
            index++;
        //here, index==n || ch!=' '
        if(index==n)
            return res;
        //确定正负号
        boolean positive = true;
        ch = str.charAt(index);
        if(ch=='-'){
            positive = false;
            index++;
        }
        else if(ch=='+'){
            positive = true;
            index++;
        }
        else if(ch<'0' || ch>'9')
            return res;
        //统计数字
        if(index==n)
            return res;
        while(index<n){
            ch = str.charAt(index);
            if(ch<'0' || ch>'9')
                //感觉还是用正负一表示比boolean方便
                return positive?res:-res;
            int cur = ch-'0';
            //检查正数是否越界
            if(positive && res > (Integer.MAX_VALUE - cur)/10)
                return Integer.MAX_VALUE;
                //检查负数是否越界; 这么写有风险, 如果cur为0那么-(Integer.MIN_VALUE + cur)就会越界, 所以先除以10, 再取负号
            else if(res > -((Integer.MIN_VALUE + cur)/10))
                return Integer.MIN_VALUE;
            //update
            res = res*10 + cur;
            index++;
        }
        return positive?res : -res;
    }
}

思路

  • 见注释
  • 关键在于如何判断上溢和下溢
第二次做, 单独处理第一个字符; 检查上溢和下溢
上溢发生的条件
10*res + curr > max
判断时得写成res > (max - curr) / 10
因为10*res + curr上溢的话就程序就在这里报错了
res > (2147483647 - curr) / 10
假设res = 2147483640, 如果curr=0,1,2,3,4,5,6,7都不会发生溢出
但是curr>=8时,上面的不等式成立,说明发生上溢

下溢发生的条件
-10*res - curr < min
res > (min + curr) / 10
res > -(-2147483648 + curr) / 10
假设res = 2147483640, 如果curr=0,1,2,3,4,5,6,7,8都不会发生下溢
但是curr>=9时,上面的不等式成立,说明发生下溢

public class Solution {
    public int StrToInt(String str) {
        if(str==null || str.length()==0)
            return 0;
        int flag=1, res=0;
        //first char
        if(str.charAt(0)=='+')
            flag=1;
        else if(str.charAt(0)=='-')
            flag=-1;
        else if(str.charAt(0)<'0' || str.charAt(0)>'9')
            return 0;
        else
            res = str.charAt(0) - '0';
        //other chars
        for(int i=1; i<str.length(); i++){
            if(str.charAt(i)<'0' || str.charAt(i) > '9')
                return 0;
            //检查是否上溢
            else if(flag==1 && res > (Integer.MAX_VALUE - (str.charAt(i)-'0'))/10)
                return 0;
            //检查下溢
            else if(flag==-1 && res > -(Integer.MIN_VALUE + (str.charAt(i)-'0'))/10)
                return 0;
            else
                res = 10*res + str.charAt(i)-'0';
        }
        return flag*res;
    }
}
第二次做, 先处理第一个字符,再统一处理剩下的字符; char-‘0’; 字符串求和问题一定要记得检查溢出,因为字符串可以表示的数的大小远超整数类型的最大值
public class Solution {
    public int StrToInt(String str) {
        if(str==null || str.length()==0)
            return 0;
        //
        int flag = 1;
        int res = 0;
        if(str.charAt(0)=='+')
            flag=1;
        else if(str.charAt(0)=='-')
            flag=-1;
        else if(str.charAt(0)<'0' || str.charAt(0)>'9')
            return 0;
        else res += 10*res + str.charAt(0) - '0';
        
        for(int i=1; i<str.length(); i++){
            if(str.charAt(i)<'0' || str.charAt(i) > '9')
                return 0;
            res = 10*res + str.charAt(i) - '0';
        }
        return res*flag;
    }
}
public class Solution {
    public int StrToInt(String str) {
        /*
        思路:
            x - '0' 
            要把特殊情况考虑全面: 空字符串, 只有正负号, 上溢, 下溢
            因为要求不合法数值均返回0, 所以把返回值初始化为0很方便
        */
        int flag=1, sum=0; // sum初始化为0很有用, 因为要求不合法数值均返回0
        for(int i=0; i<str.length(); i++){
            if(str.charAt(i)=='+')
                flag=1;
            else if(str.charAt(i)=='-')
                flag=-1;
            else if(str.charAt(i) < '0' || str.charAt(i) > '9')
                return 0;
            else if(flag==1 && (str.charAt(i) - '0' > Integer.MAX_VALUE - 10*sum)) //检查上溢
                return 0;
            else if(flag==-1 && (str.charAt(i) - '0' - 1> Integer.MAX_VALUE - 10*sum )) //检查下溢
                return 0;
            else 
                sum = 10* sum + str.charAt(i) - '0';
        }
        return flag*sum;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值