Bootstrap

【剑指Offer】个人学习笔记_67_把字符串转换成整数

刷题日期:下午5:01 2021年5月28日星期五

个人刷题记录,代码收集,来源皆为leetcode

经过多方讨论和请教,现在打算往Java方向发力

主要答题语言为Java

题目:

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

难度中等86

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

首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。

当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。

该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。

注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。

在任何情况下,若函数不能进行有效的转换时,请返回 0。

说明:

假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。

示例 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)
题目分析

题目也太长了,感觉不太能理解,学习他人

初始解答:

平均40行起的代码,还是饶了我吧,这种题真的会出吗,学习K神

class Solution {
    public int strToInt(String str) {
        int res = 0, bndry = Integer.MAX_VALUE / 10;
        int i = 0, sign = 1, length = str.length();
        if(length == 0) return 0;
        while(str.charAt(i) == ' ')
            if(++i == length) return 0;
        if(str.charAt(i) == '-') sign = -1;
        if(str.charAt(i) == '-' || str.charAt(i) == '+') i++;
        for(int j = i; j < length; j++) {
            if(str.charAt(j) < '0' || str.charAt(j) > '9') break;
            if(res > bndry || res == bndry && str.charAt(j) > '7')
                return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            res = res * 10 + (str.charAt(j) - '0');
        }
        return sign * res;
    }
}

执行结果:通过

显示详情 添加备注

执行用时:2 ms, 在所有 Java 提交中击败了99.42%的用户

内存消耗:38.6 MB, 在所有 Java 提交中击败了11.47%的用户

学习他人:

方法一:


Tai_ParkL1

(编辑过)2020-04-11

class Solution {
    public int strToInt(String str) {
    	//先去空格再判空,不然" "教您做人,血的教训
        str = str.trim();
        if(str.length() == 0){
            return 0;
        }
        //然后我想啊,下面要判断首位了
        //首位合格的无非就'+'或'-'或数字三种情况,其他的一概滚蛋
        //'+''-'肯定是要把它去掉的,这样三种情况就统一了
        //当然了,'-abc'这种有可能出现,不过只看首位它是没毛病的
        //让它进来,反正后面很容易解决
        //既然要去掉正负号,那肯定要出个boolean记一下是不是负数
        boolean isMinus = false;
        char[] ch = str.toCharArray();
        //首位是不是正负号或者数字啊
        if(ch[0] == '+' || ch[0] == '-' || Character.isDigit(ch[0])){
        	//是不是正负号啊
            if(ch[0] == '+' || ch[0] == '-'){
            	//是不是负号啊
                if(ch[0] == '-'){
                    isMinus = true;
                }
                //删除首位
                ch = Arrays.copyOfRange(ch,1,ch.length);
            }
            //首位搞定了就看后面是不是数字了,直到不是数字的地方或者倒底结束
            int index = 0;
            //结果可能超int范围,拿个long接一下
            //'-abc'这种情况返回的也是0,舒服,一箭双雕
            long res = 0;
            //短路与助您远离空指针喔,铁汁们,先后顺序关注一下
            while(index < ch.length && Character.isDigit(ch[index])){
                //一位一位往上算
                res *= 10;
                res += ch[index] - '0';
                //及时止损,一看到res超int范围立马return
                //你要是想着最后一起算,那肯定会有超long范围的测试用例等着你,你就哭去吧
                if(res > Integer.MAX_VALUE){
                    //正负号看是正数负数,返回最大值
                    return isMinus ? Integer.MIN_VALUE : Integer.MAX_VALUE;
                }
                //别忘了往后走一位
                index++;
            }
            //long转int就是这么朴实无华
            return isMinus ? -(int)res : (int)res;
        }
        //兄弟首位都不对想啥呢,回去吧您
        return 0;
    }
}

方法二:

Plius 6 小时前 java做法,时间n空间1

class Solution {
    public int strToInt(String str) {
        //符号位type
        boolean type = true;
        if(str.length() == 0) return 0;
        //len检索数字字符串中所要求数字的最后一位(最低位),index检索数字的最高位
        int len = 0, index = 0;
        //pass空格
        while(len < str.length() && str.charAt(len) == ' ') len++;
        if(len == str.length()) return 0;
        //符号位判断 true+ false-
        if(str.charAt(len) == '-'){
            type = false;
            len++;
        }else if(str.charAt(len) == '+') len++;
        //符号位后的高位0无用,直接pass
        while(len < str.length() && str.charAt(len) == '0') len++;
        //index检索有效最高位
        index = len;
        //若有效最高位不为数字或为0直接返回0
        if(len >= str.length() || str.charAt(len) < '0' || str.charAt(len) > '9') return 0;
        //len检索有效最低位
        while(len < str.length() && str.charAt(len) >= '0' && str.charAt(len) <= '9') len++;
        //MAX 2147483647 MIN -2147483648 长度均为10位,若数字有效长度超过10则直接根据type类型返回
        if(len - index > 10) return type? Integer.MAX_VALUE: Integer.MIN_VALUE;
        //进行数据检索,从有效最低为len检索到有效最高位index
        len--;
        //temp用于自乘10,num返回最终结果
        int temp = 1, num = 0;
        while(len >= index){
            //如果temp为1000000000,则代表有效数字长度为10,据此判断是否超过int范围
            //前面已经pass掉有效数字长度大于10的情况了
            if(temp == 1000000000){
                //最高位大于2,已超过int范围
                if(str.charAt(len) > '2') return type? Integer.MAX_VALUE: Integer.MIN_VALUE;
                else if(str.charAt(len) == '2'){
                    //最高位为2,根据上一循环num大小判断是否超过int范围
                    if(type){
                        if(num > 147483647) return Integer.MAX_VALUE;
                    }else{
                        if(num > 147483648) return Integer.MIN_VALUE;
                    }
                }
            }
            //int范围内的操作
            num += (str.charAt(len) - '0') * temp;
            len--;
            temp *= 10;
        }
        //根据符号位返回
        if(!type) return -num;
        return num;
    }
}

方法三:

FalseBlank
2021-05-03
这题直接把我中等提交正确率拉下来几个百分点

class Solution {
    public int strToInt(String str) {
        int n = str.length();
        long num = 0;
        boolean bl = false;
        int start = 0;
        while(start < n && str.charAt(start) == ' '){
            start++;
        }
        if(n == 0 || start == n) return 0;
        if(str.charAt(start) == '-'){
            bl = true;
            start++;
        }else if(str.charAt(start) == '+'){
            start++;
        }else if(!Character.isDigit(str.charAt(start))){
            return 0;
        }
        if(start == n) return 0;
        int i = start;
        char c = str.charAt(start);
        if(Character.isDigit(c)){
            while(i < n){
                c = str.charAt(i);
                if(!Character.isDigit(c)) break;
                int j = c - '0';
                num = num * 10 + j;
                if(num > Integer.MAX_VALUE){
                    return bl ? Integer.MIN_VALUE : Integer.MAX_VALUE;
                }
                i++;
            }
        }else{
            return 0;
        }
        return bl ? (int)(-num) : (int)num;
    }
}

方法四:

K神 根据题意,有以下四种字符需要考虑:

首部空格 符号位 非数字字符 数字字符 字符转数字 数字拼接

作者:jyd
链接:https://leetcode-cn.com/problems/ba-zi-fu-chuan-zhuan-huan-cheng-zheng-shu-lcof/solution/mian-shi-ti-67-ba-zi-fu-chuan-zhuan-huan-cheng-z-4/
来源:力扣(LeetCode)

数字越界处理:

class Solution {
    public int strToInt(String str) {
        char[] c = str.trim().toCharArray();
        if(c.length == 0) return 0;
        int res = 0, bndry = Integer.MAX_VALUE / 10;
        int i = 1, sign = 1;
        if(c[0] == '-') sign = -1;
        else if(c[0] != '+') i = 0;
        for(int j = i; j < c.length; j++) {
            if(c[j] < '0' || c[j] > '9') break;
            if(res > bndry || res == bndry && c[j] > '7') return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            res = res * 10 + (c[j] - '0');
        }
        return sign * res;
    }
}

若不使用 trim() / strip() 方法,而从头开始遍历字符串,则可以将空间复杂度降低至 O(1),代码如下:

class Solution {
    public int strToInt(String str) {
        int res = 0, bndry = Integer.MAX_VALUE / 10;
        int i = 0, sign = 1, length = str.length();
        if(length == 0) return 0;
        while(str.charAt(i) == ' ')
            if(++i == length) return 0;
        if(str.charAt(i) == '-') sign = -1;
        if(str.charAt(i) == '-' || str.charAt(i) == '+') i++;
        for(int j = i; j < length; j++) {
            if(str.charAt(j) < '0' || str.charAt(j) > '9') break;
            if(res > bndry || res == bndry && str.charAt(j) > '7')
                return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            res = res * 10 + (str.charAt(j) - '0');
        }
        return sign * res;
    }
}

总结

以上就是本题的内容和学习过程了,字符串转义,点到为止。

欢迎讨论,共同进步。

;