首页 简历|笔试面试
您现在的位置:百分网 > 职场 > 笔试面试 > LeetCode

8.字符串转换整数(atoi)

  • 25年9月4日 发布
  • 1007.9KB 共6页
8.字符串转换整数(atoi)8.字符串转换整数(atoi)8.字符串转换整数(atoi)8.字符串转换整数(atoi)8.字符串转换整数(atoi)

8. 字符串转换整数 (atoi)

题意

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数

(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

• 读入字符串并丢弃无用的前导空格

• 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。

确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。

• 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分

将被忽略。

• 将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果

没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。

• 如果整数数超过 32 位有符号整数范围 [$ -2^{31} $, $ 2^{31} $ − 1] ,需要截断这个整

数,使其保持在这个范围内。具体来说,小于 $ -2^{31} $ 的整数应该被固定为 $

-2^{31} $ ,大于 $ 2^{31} $ − 1 的整数应该被固定为 $ 2^{31} $ − 1 。

• 返回最终结果。

示例

输入:s = "42"

输出:42

第 1 步:"42"(当前没有读入字符,因为没有前导空格)

^

第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')

^

第 3 步:"42"(读入 "42",到达末尾)

^

解析得到整数 42 。由于 "42" 在 32 位有符号整数范围内,最终结果为 42 。

输入:s = " -42"

输出:-42

第 1 步:" -42"(读入前导空格,但忽视掉)

^

第 2 步:" -42"(读入 '-' 字符,所以结果应该是负数)

^

第 3 步:" -42"(读入 "42",到达末尾)

^

解析得到整数 -42 。由于 "-42" 在 32 位有符号整数范围内,最终结果为 -42 。

输入:s = "4193 with words"

输出:4193

第 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 {

public int myAtoi(String str) {

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。

比较遗憾的是,这样的代码效率不高。

008.%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%8D%A2%E6%95%B4%E

6%95%B0-20240101191651.png

分析 2

效率低的原因在于,我们在找数字的时候,已经通过 Character.isDigit() 方法判断了字

符是否为数字,但是我们还是把它存到了 StringBuilder 中,最后再通过

Integer.parseInt() 方法来转换,这样做的话,就有点多此一举了。

我们可以直接在遍历的过程中,就把数字转换出来,这样就不需要再通过

Integer.parseInt() 方法来转换了。

class Solution {

public int myAtoi(String str) {

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 < str.length() && Character.isDigit(str.charAt(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 方法的处理很接近了。

008.%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%8D%A2%E6%95%B4%E

6%95%B0-20240101193056.png

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

008.%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%8D%A2%E6%95%B4%E

6%95%B0-20240101193123.png

果然提高了一大截。

总结

如果你之前认真学过 Java 基础的话,比如说去空格,比如说判断字符的正负号,比如说

判断字符是否为数字,比如说把一个字符转成数字。

这些知识点我在《二哥的 Java 进阶之路》上都有给大家讲过,比如说:

• 判断字符是否为数字

• 把一个字符转成数字

力扣链接:https://leetcode.cn/problems/string-to-integer-atoi/

开通会员 本次下载免费

所有资料全部免费下载! 推荐用户付费下载获取返佣积分! 积分可以兑换商品!
一键复制 下载文档 联系客服