news 2026/9/16 14:08:53

LeetCode 8. 字符串转换整数 (atoi) 全解:字符处理、数字拼接与 32 位越界防护(LeetCode-Book 精选 88 题)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 8. 字符串转换整数 (atoi) 全解:字符处理、数字拼接与 32 位越界防护(LeetCode-Book 精选 88 题)

LeetCode 8. 字符串转换整数 (atoi) 全解:字符处理、数字拼接与 32 位越界防护(LeetCode-Book 精选 88 题)

【免费下载链接】LeetCode-Book《剑指 Offer》《图解算法数据结构》《Krahets 笔面试精选 88 题》Python, Java, C++ 解题代码项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Book

本篇技术指南基于 LeetCode-Book 仓库中 《Krahets 笔面试精选 88 题》题解文档.md),系统讲解 LeetCode 第 8 题“字符串转换整数 (atoi)”的完整解法:如何分四类处理输入字符、如何用res = 10 × res + x进行数字拼接,以及在“环境只能存储 32 位有符号整数”约束下,如何用边界值bndry在拼接前完成越界预判。读完本文,你将掌握一套可复现的 Python / Java / C++ 实现,并能在手写 atoi 类问题时举一反三地处理空格、符号位与溢出边界。

一、题目核心:一个字符串里藏着哪四类字符

myAtoi(s)的输入是一个任意字符串,根据题意,从左到右扫描时只需要考虑以下四种字符,其余全部忽略:

  1. 首部空格:直接跳过(删除)即可,它们不参与数值转换。
  2. 符号位:只可能出现三种情况,即'+''-'或“无符号”。需要新建一个变量保存符号位(sign),在返回结果前再乘上正负号。
  3. 非数字字符:遇到首个非数字字符时,应立即终止解析并返回当前已拼接的结果(不再向后扫描)。
  4. 数字字符:这是唯一需要“真正拼接”的字符,包含两个子步骤——字符转数字与数字拼接(详见下一节)。

这一分类贯穿整个解法:先处理空格与符号,再逐字符判断是否为数字,遇到非数字立即break/return,最后统一应用符号位。仓库源码中的注释与文档一致,例如 lc_8_string_to_integer_atoi_s1.py 按“删除首尾空格 → 判空 → 处理符号位 → 循环拼接 → 越界拦截”的顺序执行。

二、数字拼接公式:res = 10 × res + x

若从左向右遍历数字,设当前位字符为c,当前位数字为x,已拼接结果为res,则数字拼接公式为:

res = 10 × res + x x = ascii(c) - ascii('0')

其中ascii(c) - ascii('0')即“该数字字符的 ASCII 码”与“0的 ASCII 码”相减,从而把字符'0'~'9'映射为整数0~9。在三种语言的实现中分别对应:

  • Python:res = 10 * res + ord(c) - ord('0')ord取字符码点);
  • Java:res = res * 10 + (c[j] - '0')char参与算术运算时自动按码点计算);
  • C++:res = res * 10 + (s[j] - '0')

以输入" -42"为例:跳过空格后首字符为'-',置sign = -1,随后依次拼接'4''2',得到res = 42,最终返回sign * res = -42。这个“先拼绝对值、最后统一乘符号”的手法,使得正负数共用同一套拼接逻辑,代码更简洁。

三、32 位整数越界:为什么必须在拼接前拦截

题目要求返回值的范围是[-2^31, 2^31 - 1],即[-2147483648, 2147483647],并且明确指出“环境只能存储 32 位大小的有符号整数”。这意味着在拼接过程中,必须始终保持res处在 int 类型的取值范围内,否则在真正发生溢出(如 Python 大整数、C++ 有符号溢出)之前就要提前截断。

因此在每轮数字拼接之前,要先判断res在此轮拼接后是否超过2147483647,若超过则带上符号位直接返回最大值或最小值。设拼接边界:

bndry = 2147483647 // 10 = 214748364

则存在以下两种越界情况:

res > bndry 情况一:执行拼接后 10 × res ≥ 2147483650,必然越界 res == bndry 且 x > 7 情况二:拼接后为 2147483648 或 2147483649,越界

情况二需要解释:bndry × 10 + 7 = 2147483647恰好是 int 上限;若当前位数字x > 7,则拼接结果为21474836482147483649,均超出上限,必须按溢出处理。

在三种语言中,对应的判断写法分别是:

  • Python:if res > bndry or res == bndry and c > '7': return int_max if sign == 1 else int_min(用字符'7'c比较,等价于与数字 7 比较);
  • Java:if (res > bndry || res == bndry && c[j] > '7') return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
  • C++:if (res > bndry || res == bndry && s[j] > '7') return sign == 1 ? INT_MAX : INT_MIN;

其中bndry的取值也随语言略有差异,但数值等价:Python 中为2 ** 31 // 10,Java 中为Integer.MAX_VALUE / 10,C++ 中为INT_MAX / 10,结果都是214748364。仓库中 lc_8_string_to_integer_atoi_s2.java 与 lc_8_string_to_integer_atoi_s1.cpp 均以Integer.MAX_VALUE / 10INT_MAX / 10初始化该边界。

四、方案一:先trim()/strip()再解析(空间 O(N))

第一种实现直接调用语言的去空格 API,先删除首尾空格再解析,逻辑直观、最贴近题面描述。

Python 实现

class Solution: def myAtoi(self, s: str) -> int: s = s.strip() # 删除首尾空格 if not s: return 0 # 字符串为空则直接返回 res, i, sign = 0, 1, 1 int_max, int_min, bndry = 2 ** 31 - 1, -2 ** 31, 2 ** 31 // 10 if s[0] == '-': sign = -1 # 保存负号 elif s[0] != '+': i = 0 # 若无符号位,则需从 i = 0 开始数字拼接 for c in s[i:]: if not '0' <= c <= '9' : break # 遇到非数字的字符则跳出 if res > bndry or res == bndry and c > '7': return int_max if sign == 1 else int_min # 数字越界处理 res = 10 * res + ord(c) - ord('0') # 数字拼接 return sign * res

关键点在于:首字符为'-'sign = -1i = 1;首字符为'+'时保持i = 1(跳过符号位);首字符是数字或其它字符时i = 0(直接从首位开始拼接)。仓库文件 lc_8_string_to_integer_atoi_s1.py 与此实现逐行一致。

Java 实现

class Solution { public int myAtoi(String s) { char[] c = s.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; } }

方案一复杂度分析

  • 时间复杂度 O(N)N为字符串长度,线性遍历一次字符串,占用 O(N) 时间。
  • 空间复杂度 O(N):删除首尾空格后需建立新字符串(Python 的strip()、Java 的trim().toCharArray()都会产生新的字符串/字符数组对象),最差情况下占用 O(N) 额外空间。

五、方案二:手动跳过空格(空间 O(1))

若不使用trim() / strip()删除首部空格,而是改为“遍历跳过空格”的方式,则无需构造新字符串,可将空间复杂度降低至 O(1)。这也更贴近 C 语言手写atoi的经典风格。

Python 实现

class Solution: def myAtoi(self, s: str) -> int: res, i, sign, length = 0, 0, 1, len(s) int_max, int_min, bndry = 2 ** 31 - 1, -2 ** 31, 2 ** 31 // 10 if not s: return 0 # 空字符串,提前返回 while s[i] == ' ': i += 1 if i == length: return 0 # 字符串全为空格,提前返回 if s[i] == '-': sign = -1 if s[i] in '+-': i += 1 for j in range(i, length): if not '0' <= s[j] <= '9' : break if res > bndry or res == bndry and s[j] > '7': return int_max if sign == 1 else int_min res = 10 * res + ord(s[j]) - ord('0') return sign * res

该实现与前者的差异集中在两点:一是用while s[i] == ' '循环手动推进下标跳过空格,并在i到达末尾时返回0(说明字符串全为空格);二是用if s[i] in '+-': i += 1一次性跳过符号位,而不再区分'+'与无符号的情况。仓库文件 lc_8_string_to_integer_atoi_s2.py 与此实现一致。

Java 实现

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

C++ 实现

class Solution { public: int myAtoi(string s) { int res = 0, bndry = INT_MAX / 10; int i = 0, sign = 1, length = s.size(); if(length == 0) return 0; while(s[i] == ' ') if(++i == length) return 0; if(s[i] == '-') sign = -1; if(s[i] == '-' || s[i] == '+') i++; for(int j = i; j < length; j++) { if(s[j] < '0' || s[j] > '9') break; if(res > bndry || res == bndry && s[j] > '7') return sign == 1 ? INT_MAX : INT_MIN; res = res * 10 + (s[j] - '0'); } return sign * res; } };

方案二复杂度分析

  • 时间复杂度 O(N):仍为单次线性扫描,N为字符串长度。
  • 空间复杂度 O(1):全程只使用若干整数变量与下标,不创建新字符串,额外空间与输入规模无关。

六、仓库源码印证与本地运行方式

本仓库《Krahets 笔面试精选 88 题》(selected_coding_interview)为本题提供了与上述两种方案一一对应的三种语言实现,可直接对照阅读:

方案PythonJavaC++
方案一(strip/trim)lc_8_string_to_integer_atoi_s1.pylc_8_string_to_integer_atoi_s1.java
方案二(手动跳空格)lc_8_string_to_integer_atoi_s2.pylc_8_string_to_integer_atoi_s2.javalc_8_string_to_integer_atoi_s1.cpp

从源码结构看,Python 与 Java 均给出 s1/s2 两版实现,C++ 则直接采用空间 O(1) 的手动跳空格版本,恰好印证了“优先使用 O(1) 空间写法”这一实践倾向。源码文件统一以from include import *(Python)、package lc_8_string_to_integer_atoi; import include.*;(Java)、#include "../include/include.hpp"(C++)引入仓库公共头文件,并附带main/ 驱动代码与测试用例占位,可在此基础上替换test_input验证各类输入:

# 以 Python 方案一为例 from include import * class Solution: def myAtoi(self, s: str) -> int: s = s.strip() if not s: return 0 res, i, sign = 0, 1, 1 int_max, int_min, bndry = 2 ** 31 - 1, -2 ** 31, 2 ** 31 // 10 if s[0] == '-': sign = -1 elif s[0] != '+': i = 0 for c in s[i:]: if not '0' <= c <= '9' : break if res > bndry or res == bndry and c > '7': return int_max if sign == 1 else int_min res = 10 * res + ord(c) - ord('0') return sign * res slt = Solution() for t in [" -42", "4193 with words", "words and 987", "-91283472332", "+1", " ", "2147483648"]: print(f"{t!r:>20} -> {slt.myAtoi(t)}")

建议用以下用例自测,覆盖题面全部边界:

  • " -42"-42(前导空格 + 负号);
  • "4193 with words"4193(数字后遇到非数字截断);
  • "words and 987"0(首个非空字符非数字,直接返回 0);
  • "-91283472332"-2147483648(负向越界,返回INT_MIN);
  • "2147483648"2147483647(正向越界,返回INT_MAX);
  • " "0(全空格,方案二在跳空格时提前返回)。

七、小结:这道题在考什么

字符串转换整数 (atoi) 是面试中典型的“模拟 + 边界”题,考点集中在:

  1. 字符分类能力:能否条理清晰地处理空格、符号、非数字与数字四类情况;
  2. 数字拼接功底res = 10 × res + x与 ASCII 码相减取数字;
  3. 越界防御思维:在 32 位 int 约束下,用bndry = INT_MAX / 10结合“res > bndryres == bndry && 当前位 > 7”在拼接前拦截溢出,而不是等溢出发生后再补救;
  4. 空间优化意识:同一逻辑可写出空间 O(N)(依赖strip/trim)与空间 O(1)(手动跳空格)两种版本,理解二者的取舍。

本仓库对应的剑指 Offer 版本题解位于 sword_for_offer/docs/剑指 Offer 67. 把字符串转换成整数.md,可对照学习同一考点在《剑指 Offer》中的变体考查方式;更多“模拟 + 边界”类题目与配套三语言代码,可在 selected_coding_interview 目录下按题目编号继续检索。

【免费下载链接】LeetCode-Book《剑指 Offer》《图解算法数据结构》《Krahets 笔面试精选 88 题》Python, Java, C++ 解题代码项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Book

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 14:08:13

Python文件操作与IO流详解:从基础到高级技巧

1. Python文件操作基础与IO流概念1.1 理解IO的本质在编程中&#xff0c;IO&#xff08;Input/Output&#xff09;是程序与外部世界交互的桥梁。想象你正在用手机拍照&#xff1a;按下快门是输入&#xff08;Input&#xff09;&#xff0c;保存照片到相册是输出&#xff08;Outp…

作者头像 李华
网站建设 2026/9/16 14:06:42

NLTK与PyTorch结合:文本分类预处理到模型设计完整源码

简介&#xff1a;一份基于深度学习的自动文本分类系统设计源码&#xff0c;采用Python与NLTK工具库开发&#xff0c;面向需要处理文本归类、情感分析、垃圾邮件识别等场景的开发者与研究者&#xff0c;适合快速构建和扩展分类模型。资源包共37个文件&#xff0c;其中16个Python…

作者头像 李华
网站建设 2026/9/16 14:04:58

simulink寄生参数对逆变器波形的影响建模方法

目录 一、为什么要加入 寄生参数&#xff08;Parasitic&#xff09; 二、目标&#xff08;本次仿真&#xff09; 三、关键参数 四、Simulink 建模&#xff08;手把手&#xff09; 4.1 Step 1️⃣ —— 功率级&#xff08;三种可切换&#xff09; ■ DC‑Link 杂散电感 ■…

作者头像 李华
网站建设 2026/9/16 14:01:14

STM32实战:RGB三色灯数据通过串口帧上报调试助手

简介&#xff1a;这是一套基于STM32单片机的多功能综合实训源码&#xff0c;面向嵌入式初学者和电子设计爱好者&#xff0c;解决RGB三色灯控制、OLED显示、蜂鸣器报警及串口数据调试的一体化开发需求。项目使用C语言编写&#xff0c;涵盖GPIO、定时器PWM、I2C/SPI驱动OLED、串口…

作者头像 李华