008.字符串转换整数(atoi)
作者:沉默王二 发布时间:2024-01-01T20:35:51.148+0800
-
语雀专栏地址+密码可通过星球置顶帖查看:https://t.zsxq.com/15rEo9Pdu
-
技术派专栏地址:https://paicoding.com/column/7/8
-
这道题可以说完全重写了,给出两道大家完全都能掌握的题解,并且追加手绘图,大家会非常容易掌握,一道中等难度直接变身 easy 难度。
-
增加代码注释,这样大家更容易看懂并掌握题解;
-
增加参考资料,这样大家可以从零基础直接开刷,减轻新手刷题的阻力;
-
增加手绘图,这样大家更容易理解解题思路;
-
增加 ACM 输入输出,这样大家可以在 Intellij IDEA 中进行调试;
-
增加题解模拟,这样大家可以根据题解模拟整个题解过程,看完会有一种“哦哦”恍然大悟的感觉;
-
图片上传至 OSS 并配合 CDN,提升大家在技术派网站中的阅读体感。
-
另外,这一版本会作为 PDF 的终稿随后在星球进行发布。
题意
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:
- 读入字符串并丢弃无用的前导空格
- 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
- 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
- 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
- 如果整数数超过 32 位有符号整数范围 [, − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 的整数应该被固定为 ,大于 − 1 的整数应该被固定为 − 1 。
- 返回最终结果。
示例
输入:s = "42"
第 1 步:"42"(当前没有读入字符,因为没有前导空格) ^第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+') ^第 3 步:"42"(读入 "42",到达末尾) ^解析得到整数 42 。由于 "42" 在 32 位有符号整数范围内,最终结果为 42 。
输入:s = " -42"
第 1 步:" -42"(读入前导空格,但忽视掉) ^第 2 步:" -42"(读入 '-' 字符,所以结果应该是负数) ^第 3 步:" -42"(读入 "42",到达末尾) ^解析得到整数 -42 。由于 "-42" 在 32 位有符号整数范围内,最终结果为 -42 。
输入:s = "4193 with words"
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格) ^第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+') ^第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止) ^解析得到整数 4193 。由于 "4193" 在 32 位有符号整数范围内,最终结果为 4193 。
难度
中
分析 1
其实这道题的描述对于 Java 党来说,实在是不够友好,在 Java 中,我们都喜欢叫“方法”而不是函数,更没有 atoi 函数。
不过,读完这道题目,很容易联想到 Java 当中的 Integer.parseInt() 方法,这个方法就是来完成数字字符串转整数的,对吧?
我之前在《二哥的 Java 进阶之路 》上也带大家分析过该方法的源码,不过 parseInt 方法仅处理了正负的情况,并没有处理空格的情况、字符串中包含字符的情况,不过我们可以在此基础上进行扩展,来完成这道题目。
①、处理空格我们就用 String 的 trim() 方法来完成。
②、接着我们需要把字符串中数字部分找出来,这里我们可以通过 Character.isDigit() 方法来完成。我们在讲**基本数据类型的包装器类型 **时曾讲过这个方法,不知道大家还记得不?
唯一需要注意的是,我们需要考虑正负号的情况,所以我们需要在找到正负号后,再往后找数字。
class Solution {
if (str == null || str.length() == 0) { return 0; }
str = str.trim(); // 去除前导空格 if (str.length() == 0) return 0;
int sign = 1; int index = 0;
// 检查正负号 if (str.charAt(0) == '+' || str.charAt(0) == '-') { sign = str.charAt(0) == '-' ? -1 : 1; index++; }
// 提取数字 StringBuilder numberStr = new StringBuilder(); while (index < str.length() && Character.isDigit(str.charAt(index))) { numberStr.append(str.charAt(index)); index++; }
// 没有数字 if (numberStr.length() == 0) { return 0; }
// 尝试转换 try { return Integer.parseInt(numberStr.toString()) * sign; } catch (NumberFormatException e) { return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; } }}
代码非常简单,先去掉空格,再判断正负,然后遍历字符串,找出数字的部分,最后尝试通过 Integer.parseInt() 方法来转换,如果转换失败,就返回 Integer.MIN_VALUE 或者 Integer.MAX_VALUE。
比较遗憾的是,这样的代码效率不高。
分析 2
效率低的原因在于,我们在找数字的时候,已经通过 Character.isDigit() 方法判断了字符是否为数字,但是我们还是把它存到了 StringBuilder 中,最后再通过 Integer.parseInt() 方法来转换,这样做的话,就有点多此一举了。
我们可以直接在遍历的过程中,就把数字转换出来,这样就不需要再通过 Integer.parseInt() 方法来转换了。
class Solution {
if (str == null || str.length() == 0) { return 0; }
str = str.trim(); // 去除前导空格 if (str.length() == 0) return 0;
int sign = 1; int index = 0;
// 检查正负号 if (str.charAt(0) == '+' || str.charAt(0) == '-') { sign = str.charAt(0) == '-' ? -1 : 1; index++; }
// 提取数字 int result = 0; while (index < str.length() && Character.isDigit(str.charAt(index))) { int digit = str.charAt(index) - '0'; if (result > (Integer.MAX_VALUE - digit) / 10) { return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; } result = result * 10 + digit; index++; }
return result * sign; }}
while 循环前面都很好懂,我来详细解释一下 while 循环中的代码:
while (index int digit = str.charAt(index) - '0';
// 溢出检查:如果当前的 result 大于最大整数减去当前数字除以 10, // 则表示下一步操作(result * 10 + digit)会导致溢出 if (result > (Integer.MAX_VALUE - digit) / 10) { // 根据符号返回最大或最小整数 return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; }
// 更新结果:将当前数字累加到结果中 result = result * 10 + digit;
// 移动到字符串的下一个字符 index++;}
- **循环条件**:index < [str.length](http://str.length)() && Character.isDigit(str.charAt(index)) 确保只有在字符串没有结束且当前字符是数字时,循环才继续。
- **字符转数字**:int digit = str.charAt(index) - '0'; 将字符型的数字转换为整型。在 ASCII 码表中,数字字符 '0' 到 '9' 是连续排列的,所以 str.charAt(index) - '0' 能够得到相应的整数值。
- **溢出检查**:if (result > (Integer.MAX_VALUE - digit) / 10) 检查是否即将发生溢出。因为下一步操作是 result * 10 + digit,如果 result 已经大于 (Integer.MAX_VALUE - digit) / 10,则乘以 10 后加上 digit 一定会超出 int 的范围。这里使用 (Integer.MAX_VALUE - digit) / 10 作为阈值来避免在乘法之后才检测溢出,那时可能已经晚了。
- **更新结果**:result = result * 10 + digit; 将当前数字字符的值累加到 result 中。这里的 result * 10 是为了将之前的结果左移一位(即乘以 10),然后加上当前的数字。
这个 while 循环就很精巧,其实就和 parseInt 方法的处理很接近了。

OK,我们再来看一下运行效率。

果然提高了一大截。
### **总结**
如果你之前认真学过 Java 基础的话,比如说去空格,比如说判断字符的正负号,比如说判断字符是否为数字,比如说把一个字符转成数字。
这些知识点我在《二哥的 Java 进阶之路》上都有给大家讲过,比如说:
- **[判断字符是否为数字](https://javabetter.cn/basic-grammar/basic-data-type.html)**
- **[把一个字符转成数字](https://javabetter.cn/basic-grammar/basic-data-type.html#_04%E3%80%81int-%E5%92%8C-char-%E7%B1%BB%E5%9E%8B%E4%BA%92%E8%BD%AC)**
力扣链接:**[https://leetcode.cn/problems/string-to-integer-atoi/](https://leetcode.cn/problems/string-to-integer-atoi/)**
### **一步一个脚印**
不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。
该题解目前只针对**[二哥编程星球](https://javabetter.cn/zhishixingqiu/)**的球友开放,如果你也想一起打卡学习算法的话,扫下面的优惠券加入我们吧,星球目前 4100+ 人,定价 149 元,从当初的 99 元一路涨上来的,所以早就是优势,别再犹豫了。

(优惠券仅 300 张,数量有限)
一个人可以走得很快,但一群人才能走得更远。如果想去面中大厂的话,LeetCode 几乎是必刷的,二哥的 LeetCode 题解通俗易懂、图文并茂,理解给你举一反三的解题能力,冲鸭。
- 语雀专栏地址+密码可通过星球置顶帖查看:[https://t.zsxq.com/15rEo9Pdu](https://t.zsxq.com/15rEo9Pdu)
- 技术派专栏地址:[https://paicoding.com/column/7/8](https://paicoding.com/column/7/8)
- 星球原地址:[https://t.zsxq.com/15u5YkmHY](https://t.zsxq.com/15u5YkmHY)
- 这道题可以说完全重写了,给出两道大家完全都能掌握的题解,并且追加手绘图,大家会非常容易掌握,一道中等难度直接变身 easy 难度。
- 增加代码注释,这样大家更容易看懂并掌握题解;
- 增加参考资料,这样大家可以从零基础直接开刷,减轻新手刷题的阻力;
- 增加手绘图,这样大家更容易理解解题思路;
- 增加 ACM 输入输出,这样大家可以在 Intellij IDEA 中进行调试;
- 增加题解模拟,这样大家可以根据题解模拟整个题解过程,看完会有一种“哦哦”恍然大悟的感觉;
- 图片上传至 OSS 并配合 CDN,提升大家在技术派网站中的阅读体感。
- 另外,这一版本会作为 PDF 的终稿随后在星球进行发布。
### **题意**
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:
- 读入字符串并丢弃无用的前导空格
- 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
- 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
- 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
- 如果整数数超过 32 位有符号整数范围 [, − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 的整数应该被固定为 ,大于 − 1 的整数应该被固定为 − 1 。
- 返回最终结果。
### **示例**
输入:s = "42"
第 1 步:"42"(当前没有读入字符,因为没有前导空格) ^第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+') ^第 3 步:"42"(读入 "42",到达末尾) ^解析得到整数 42 。由于 "42" 在 32 位有符号整数范围内,最终结果为 42 。
输入:s = " -42"
第 1 步:" -42"(读入前导空格,但忽视掉) ^第 2 步:" -42"(读入 '-' 字符,所以结果应该是负数) ^第 3 步:" -42"(读入 "42",到达末尾) ^解析得到整数 -42 。由于 "-42" 在 32 位有符号整数范围内,最终结果为 -42 。
输入:s = "4193 with words"
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格) ^第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+') ^第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止) ^解析得到整数 4193 。由于 "4193" 在 32 位有符号整数范围内,最终结果为 4193 。
### **难度**
中
### **分析 1**
其实这道题的描述对于 Java 党来说,实在是不够友好,在 Java 中,我们都喜欢叫“方法”而不是函数,更没有 atoi 函数。
不过,读完这道题目,很容易联想到 Java 当中的 **[Integer.parseInt()](https://javabetter.cn/basic-grammar/basic-data-type.html#_05%E3%80%81%E5%8C%85%E8%A3%85%E5%99%A8%E7%B1%BB%E5%9E%8B)** 方法,这个方法就是来完成数字字符串转整数的,对吧?
我之前在《**[二哥的 Java 进阶之路](https://javabetter.cn/basic-grammar/basic-data-type.html)**》上也带大家分析过该方法的源码,不过 parseInt 方法仅处理了正负的情况,并没有处理空格的情况、字符串中包含字符的情况,不过我们可以在此基础上进行扩展,来完成这道题目。
①、处理空格我们就用 String 的 trim() 方法来完成。
②、接着我们需要把字符串中数字部分找出来,这里我们可以通过 Character.isDigit() 方法来完成。我们在讲**[基本数据类型的包装器类型](https://javabetter.cn/basic-grammar/basic-data-type.html)**时曾讲过这个方法,不知道大家还记得不?
唯一需要注意的是,我们需要考虑正负号的情况,所以我们需要在找到正负号后,再往后找数字。
class Solution {
if (str == null || str.length() == 0) { return 0; }
str = str.trim(); // 去除前导空格 if (str.length() == 0) return 0;
int sign = 1; int index = 0;
// 检查正负号 if (str.charAt(0) == '+' || str.charAt(0) == '-') { sign = str.charAt(0) == '-' ? -1 : 1; index++; }
// 提取数字 StringBuilder numberStr = new StringBuilder(); while (index < str.length() && Character.isDigit(str.charAt(index))) { numberStr.append(str.charAt(index)); index++; }
// 没有数字 if (numberStr.length() == 0) { return 0; }
// 尝试转换 try { return Integer.parseInt(numberStr.toString()) * sign; } catch (NumberFormatException e) { return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; } }}
代码非常简单,先去掉空格,再判断正负,然后遍历字符串,找出数字的部分,最后尝试通过 Integer.parseInt() 方法来转换,如果转换失败,就返回 Integer.MIN_VALUE 或者 Integer.MAX_VALUE。
比较遗憾的是,这样的代码效率不高。

### **分析 2**
效率低的原因在于,我们在找数字的时候,已经通过 Character.isDigit() 方法判断了字符是否为数字,但是我们还是把它存到了 StringBuilder 中,最后再通过 Integer.parseInt() 方法来转换,这样做的话,就有点多此一举了。
我们可以直接在遍历的过程中,就把数字转换出来,这样就不需要再通过 Integer.parseInt() 方法来转换了。
class Solution {
if (str == null || str.length() == 0) { return 0; }
str = str.trim(); // 去除前导空格 if (str.length() == 0) return 0;
int sign = 1; int index = 0;
// 检查正负号 if (str.charAt(0) == '+' || str.charAt(0) == '-') { sign = str.charAt(0) == '-' ? -1 : 1; index++; }
// 提取数字 int result = 0; while (index < str.length() && Character.isDigit(str.charAt(index))) { int digit = str.charAt(index) - '0'; if (result > (Integer.MAX_VALUE - digit) / 10) { return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; } result = result * 10 + digit; index++; }
return result * sign; }}
while 循环前面都很好懂,我来详细解释一下 while 循环中的代码:
while (index int digit = str.charAt(index) - '0'; // 溢出检查:如果当前的 result 大于最大整数减去当前数字除以 10, // 则表示下一步操作(result * 10 + digit)会导致溢出 if (result > (Integer.MAX_VALUE - digit) / 10) { // 根据符号返回最大或最小整数 return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; } // 更新结果:将当前数字累加到结果中 result = result * 10 + digit; // 移动到字符串的下一个字符 index++;}
- 循环条件:index < str.length () && Character.isDigit(str.charAt(index)) 确保只有在字符串没有结束且当前字符是数字时,循环才继续。
- 字符转数字:int digit = str.charAt(index) - '0'; 将字符型的数字转换为整型。在 ASCII 码表中,数字字符 '0' 到 '9' 是连续排列的,所以 str.charAt(index) - '0' 能够得到相应的整数值。
- 溢出检查:if (result > (Integer.MAX_VALUE - digit) / 10) 检查是否即将发生溢出。因为下一步操作是 result * 10 + digit,如果 result 已经大于 (Integer.MAX_VALUE - digit) / 10,则乘以 10 后加上 digit 一定会超出 int 的范围。这里使用 (Integer.MAX_VALUE - digit) / 10 作为阈值来避免在乘法之后才检测溢出,那时可能已经晚了。
- 更新结果:result = result * 10 + digit; 将当前数字字符的值累加到 result 中。这里的 result * 10 是为了将之前的结果左移一位(即乘以 10),然后加上当前的数字。
这个 while 循环就很精巧,其实就和 parseInt 方法的处理很接近了。
OK,我们再来看一下运行效率。
果然提高了一大截。
总结
如果你之前认真学过 Java 基础的话,比如说去空格,比如说判断字符的正负号,比如说判断字符是否为数字,比如说把一个字符转成数字。
这些知识点我在《二哥的 Java 进阶之路》上都有给大家讲过,比如说:
力扣链接:https://leetcode.cn/problems/string-to-integer-atoi/
一步一个脚印
不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。
该题解目前只针对**二哥编程星球 **的球友开放,如果你也想一起打卡学习算法的话,扫下面的优惠券加入我们吧,星球目前 4100+ 人,定价 149 元,从当初的 99 元一路涨上来的,所以早就是优势,别再犹豫了。
(优惠券仅 300 张,数量有限)
一个人可以走得很快,但一群人才能走得更远。如果想去面中大厂的话,LeetCode 几乎是必刷的,二哥的 LeetCode 题解通俗易懂、图文并茂,理解给你举一反三的解题能力,冲鸭。
- 语雀专栏地址+密码可通过星球置顶帖查看:[https://t.zsxq.com/15rEo9Pdu](https://t.zsxq.com/15rEo9Pdu)
-
技术派专栏地址:https://paicoding.com/column/7/8
-
这道题可以说完全重写了,给出两道大家完全都能掌握的题解,并且追加手绘图,大家会非常容易掌握,一道中等难度直接变身 easy 难度。
-
增加代码注释,这样大家更容易看懂并掌握题解;
-
增加参考资料,这样大家可以从零基础直接开刷,减轻新手刷题的阻力;
-
增加手绘图,这样大家更容易理解解题思路;
-
增加 ACM 输入输出,这样大家可以在 Intellij IDEA 中进行调试;
-
增加题解模拟,这样大家可以根据题解模拟整个题解过程,看完会有一种“哦哦”恍然大悟的感觉;
-
图片上传至 OSS 并配合 CDN,提升大家在技术派网站中的阅读体感。
-
另外,这一版本会作为 PDF 的终稿随后在星球进行发布。
题意
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:
- 读入字符串并丢弃无用的前导空格
- 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
- 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
- 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
- 如果整数数超过 32 位有符号整数范围 [, − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 的整数应该被固定为 ,大于 − 1 的整数应该被固定为 − 1 。
- 返回最终结果。
示例
输入:s = "42"
第 1 步:"42"(当前没有读入字符,因为没有前导空格) ^第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+') ^第 3 步:"42"(读入 "42",到达末尾) ^解析得到整数 42 。由于 "42" 在 32 位有符号整数范围内,最终结果为 42 。
输入:s = " -42"
第 1 步:" -42"(读入前导空格,但忽视掉) ^第 2 步:" -42"(读入 '-' 字符,所以结果应该是负数) ^第 3 步:" -42"(读入 "42",到达末尾) ^解析得到整数 -42 。由于 "-42" 在 32 位有符号整数范围内,最终结果为 -42 。
输入:s = "4193 with words"
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格) ^第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+') ^第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止) ^解析得到整数 4193 。由于 "4193" 在 32 位有符号整数范围内,最终结果为 4193 。
难度
中
分析 1
其实这道题的描述对于 Java 党来说,实在是不够友好,在 Java 中,我们都喜欢叫“方法”而不是函数,更没有 atoi 函数。
不过,读完这道题目,很容易联想到 Java 当中的 Integer.parseInt() 方法,这个方法就是来完成数字字符串转整数的,对吧?
我之前在《二哥的 Java 进阶之路 》上也带大家分析过该方法的源码,不过 parseInt 方法仅处理了正负的情况,并没有处理空格的情况、字符串中包含字符的情况,不过我们可以在此基础上进行扩展,来完成这道题目。
①、处理空格我们就用 String 的 trim() 方法来完成。
②、接着我们需要把字符串中数字部分找出来,这里我们可以通过 Character.isDigit() 方法来完成。我们在讲**基本数据类型的包装器类型 **时曾讲过这个方法,不知道大家还记得不?
唯一需要注意的是,我们需要考虑正负号的情况,所以我们需要在找到正负号后,再往后找数字。
class Solution {
if (str == null || str.length() == 0) { return 0; }
str = str.trim(); // 去除前导空格 if (str.length() == 0) return 0;
int sign = 1; int index = 0;
// 检查正负号 if (str.charAt(0) == '+' || str.charAt(0) == '-') { sign = str.charAt(0) == '-' ? -1 : 1; index++; }
// 提取数字 StringBuilder numberStr = new StringBuilder(); while (index < str.length() && Character.isDigit(str.charAt(index))) { numberStr.append(str.charAt(index)); index++; }
// 没有数字 if (numberStr.length() == 0) { return 0; }
// 尝试转换 try { return Integer.parseInt(numberStr.toString()) * sign; } catch (NumberFormatException e) { return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; } }}
代码非常简单,先去掉空格,再判断正负,然后遍历字符串,找出数字的部分,最后尝试通过 Integer.parseInt() 方法来转换,如果转换失败,就返回 Integer.MIN_VALUE 或者 Integer.MAX_VALUE。
比较遗憾的是,这样的代码效率不高。
分析 2
效率低的原因在于,我们在找数字的时候,已经通过 Character.isDigit() 方法判断了字符是否为数字,但是我们还是把它存到了 StringBuilder 中,最后再通过 Integer.parseInt() 方法来转换,这样做的话,就有点多此一举了。
我们可以直接在遍历的过程中,就把数字转换出来,这样就不需要再通过 Integer.parseInt() 方法来转换了。
class Solution {
if (str == null || str.length() == 0) { return 0; }
str = str.trim(); // 去除前导空格 if (str.length() == 0) return 0;
int sign = 1; int index = 0;
// 检查正负号 if (str.charAt(0) == '+' || str.charAt(0) == '-') { sign = str.charAt(0) == '-' ? -1 : 1; index++; }
// 提取数字 int result = 0; while (index < str.length() && Character.isDigit(str.charAt(index))) { int digit = str.charAt(index) - '0'; if (result > (Integer.MAX_VALUE - digit) / 10) { return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; } result = result * 10 + digit; index++; }
return result * sign; }}
while 循环前面都很好懂,我来详细解释一下 while 循环中的代码:
while (index int digit = str.charAt(index) - '0';
// 溢出检查:如果当前的 result 大于最大整数减去当前数字除以 10, // 则表示下一步操作(result * 10 + digit)会导致溢出 if (result > (Integer.MAX_VALUE - digit) / 10) { // 根据符号返回最大或最小整数 return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE; }
// 更新结果:将当前数字累加到结果中 result = result * 10 + digit;
// 移动到字符串的下一个字符 index++;}
- **循环条件**:index < [str.length](http://str.length)() && Character.isDigit(str.charAt(index)) 确保只有在字符串没有结束且当前字符是数字时,循环才继续。
- **字符转数字**:int digit = str.charAt(index) - '0'; 将字符型的数字转换为整型。在 ASCII 码表中,数字字符 '0' 到 '9' 是连续排列的,所以 str.charAt(index) - '0' 能够得到相应的整数值。
- **溢出检查**:if (result > (Integer.MAX_VALUE - digit) / 10) 检查是否即将发生溢出。因为下一步操作是 result * 10 + digit,如果 result 已经大于 (Integer.MAX_VALUE - digit) / 10,则乘以 10 后加上 digit 一定会超出 int 的范围。这里使用 (Integer.MAX_VALUE - digit) / 10 作为阈值来避免在乘法之后才检测溢出,那时可能已经晚了。
- **更新结果**:result = result * 10 + digit; 将当前数字字符的值累加到 result 中。这里的 result * 10 是为了将之前的结果左移一位(即乘以 10),然后加上当前的数字。
这个 while 循环就很精巧,其实就和 parseInt 方法的处理很接近了。

OK,我们再来看一下运行效率。

果然提高了一大截。
### **总结**
如果你之前认真学过 Java 基础的话,比如说去空格,比如说判断字符的正负号,比如说判断字符是否为数字,比如说把一个字符转成数字。
这些知识点我在《二哥的 Java 进阶之路》上都有给大家讲过,比如说:
- **[判断字符是否为数字](https://javabetter.cn/basic-grammar/basic-data-type.html)**
- **[把一个字符转成数字](https://javabetter.cn/basic-grammar/basic-data-type.html#_04%E3%80%81int-%E5%92%8C-char-%E7%B1%BB%E5%9E%8B%E4%BA%92%E8%BD%AC)**
力扣链接:**[https://leetcode.cn/problems/string-to-integer-atoi/](https://leetcode.cn/problems/string-to-integer-atoi/)**
### **一步一个脚印**
不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。
该题解目前只针对**[二哥编程星球](https://javabetter.cn/zhishixingqiu/)**的球友开放,如果你也想一起打卡学习算法的话,扫下面的优惠券加入我们吧,星球目前 4100+ 人,定价 149 元,从当初的 99 元一路涨上来的,所以早就是优势,别再犹豫了。

(优惠券仅 300 张,数量有限)
一个人可以走得很快,但一群人才能走得更远。如果想去面中大厂的话,LeetCode 几乎是必刷的,二哥的 LeetCode 题解通俗易懂、图文并茂,理解给你举一反三的解题能力,冲鸭。
知识星球
扫码加入星球
查看更多优质内容
https://wx.zsxq.com/mweb/views/joingroup/join_group.html?group_id=15522885221412