字符串转换整数 (atoi) 图解题解
跳空格、认符号、逐位拼数、钳范围——四步流水线,一遍扫完实现 atoi。
就像收银员读收据:先跳过开头的空白,认一下有没有正负号,然后逐位读数字(每多一位就把已读的数乘十再加进去),遇到第一个非数字字符立刻停手,最后把结果夹到整数上下限之间——四个阶段,顺序不乱、遇阻即停。
这道题到底在问什么
- 输入
- s = " -42abc"
- 输出
- -42 (跳过空格→负号→读 42→遇 a 停)
- 输入
- s = "4193 with words"
- 输出
- 4193 (读到空格就停)
最优解:一步一步想明白
- 3记住这四步顺序,下面每一帧都在套它。
- 4把字符串摊成一格一格。橙色指针从最左边出发,逐个字符往右走。右下角的 RESULT 实时显示「现在在第几步、正负、累加到多少」。
- 5下标 0 是空格。规则第一步「跳过前导空格」——什么都不做,指针往右挪一格。开头的空格全这样一个个跳掉。
- 6下标 1 是空格。规则第一步「跳过前导空格」——什么都不做,指针往右挪一格。开头的空格全这样一个个跳掉。
- 7下标 2 是符号「-」。空格跳完后,紧接着的第一个 +/- 决定正负——这里是「-」,所以结果是负数。符号只认这一个,之后再出现 +/- 都算非法、会触发停。
- 8下标 3 是数字 4。读数字的核心公式:num = num × 10 + 当前位。先把原来的 0 乘 10「腾出个位」,再把 4 加上去。下一帧落值。
- 9落值:num 变成 4。绿色高亮的就是目前已经吃进结果的数字位。继续往后看下一个字符是不是数字。
- 10下标 4 是数字 2。读数字的核心公式:num = num × 10 + 当前位。先把原来的 4 乘 10「腾出个位」,再把 2 加上去。下一帧落值。
- 11落值:num 变成 42。绿色高亮的就是目前已经吃进结果的数字位。继续往后看下一个字符是不是数字。
- 12下标 5 是「a」,不是数字——读数字阶段遇到第一个非数字就立刻停,后面的「abc」一律不看。把累加出的 42 乘上符号,最终结果 -42。
- 13回看整条路径:蓝色是跳过的空格和符号,绿色是真正构成数字的那几位。指针从左到右只走一遍,O(n)。这就是「状态机」——每个字符只看一次,按当前阶段决定怎么处理。
⚠️ 容易写错的地方
✗ 错:先把整串数字读完再判溢出
✓ 对:每累加一位就立刻判一次是否超 int
读完再判,num 早就溢出成乱码,判断失真;边读边判才稳
✗ 错:用 int 存 num
✓ 对:用 long(或溢出前预判)存累加值
int 存累加值,超界瞬间自己就溢出回绕,无法正确截断
✗ 错:空格 / 符号顺序读乱
✓ 对:严格按「先空格、再符号、最后数字」一次性顺序
比如 "+ 42"(符号后有空格)、"--42"(两个符号)都非法,乱序会误读
完整代码(Python / C++ / Java)
Python
def myAtoi(s: str) -> int:
INT_MAX, INT_MIN = 2**31 - 1, -2**31
i, n = 0, len(s)
while i < n and s[i] == " ": i += 1 # ① 跳空格
sign = 1
if i < n and s[i] in "+-": # ② 读符号
sign = -1 if s[i] == "-" else 1
i += 1
num = 0
while i < n and s[i].isdigit(): # ③ 逐位累加
num = num * 10 + (ord(s[i]) - ord("0"))
if sign * num <= INT_MIN: return INT_MIN # ④ 截断
if sign * num >= INT_MAX: return INT_MAX
i += 1
return sign * numC++
int myAtoi(string s) {
int i = 0, n = s.size(), sign = 1; long num = 0;
while (i < n && s[i] == ' ') i++; // ① 跳空格
if (i < n && (s[i]=='+'||s[i]=='-')) // ② 读符号
sign = s[i++] == '-' ? -1 : 1;
while (i < n && isdigit(s[i])) { // ③ 逐位累加
num = num * 10 + (s[i++] - '0');
if (sign * num < INT_MIN) return INT_MIN; // ④ 截断
if (sign * num > INT_MAX) return INT_MAX;
}
return (int)(sign * num);
}Java
public int myAtoi(String s) {
int i = 0, n = s.length(), sign = 1;
long num = 0;
while (i < n && s.charAt(i) == ' ') i++; // ① 跳空格
if (i < n && (s.charAt(i)=='+'||s.charAt(i)=='-')) // ② 读符号
sign = s.charAt(i++) == '-' ? -1 : 1;
while (i < n && Character.isDigit(s.charAt(i))) { // ③ 逐位累加
num = num * 10 + (s.charAt(i++) - '0');
if (sign * num < Integer.MIN_VALUE) // ④ 截断
return Integer.MIN_VALUE;
if (sign * num > Integer.MAX_VALUE)
return Integer.MAX_VALUE;
}
return (int)(sign * num);复杂度
时间
O(n)
每个字符最多看一次,指针只向右走一遍
空间
O(1)
只用几个变量 i / sign / num,不开额外结构
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 字符串转换整数 (atoi) 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么不直接用语言自带的 int(s) / Integer.parseInt?+
自带函数遇到非法字符会抛异常或行为不符本题规则(本题要求遇非数字静默停、超界截断而非报错)。手写状态机才能精确控制每一步。
怎么处理「+ 42」这种符号后有空格的?+
按规则,符号后必须紧跟数字。读完符号后下一个是空格,不是数字,直接进入「遇非数字停」,结果为 0。顺序严格不回头。
如果允许前后都有空格、中间也有逗号分隔呢?+
那是另一套解析规则(更接近完整的词法分析)。本题只解析「最前面那一段合法整数」,遇到第一个不符合的字符就停。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 字符串转换整数 (atoi) 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。