字符串转换整数 (atoi)
在 LeetCode 上查看 ↗语音讲解
开车或通勤时可听,跟着思路走一遍
速度
题目描述
请你实现一个 myAtoi(string s) 函数,将字符串转换成一个 32 位有符号整数。规则:先丢弃前导空格;然后可选地读取一个正负号;接着尽可能多地读取连续数字;将结果限制在 [−2³¹, 2³¹−1] 内,越界则取边界值。
示例 1
输入:s = "42"
输出:42
示例 2
输入:s = " -42 abc"
输出:-42
示例 3
输入:s = "words and 987"
输出:0(第一个非空字符不是数字或符号)
模拟答题者思考
1. 这是一道模拟题,关键是严格按「空格 → 符号 → 数字」的顺序处理,遇到非法就停。
2. 只在开头跳一次前导空格;符号最多一个;数字一直读到非数字为止。
3. 溢出处理:每累加一位就检查 sign*num 是否已超出 32 位范围,超了直接返回边界值。
4. 首个有效字符若不是数字或符号,直接返回 0。
变量语义(先读这三句再编码)
| 变量 | 类型 | 语义(三句法) |
|---|---|---|
i | int | 定义:当前扫描到的位置 维护:依次跳过空格、符号、数字 更新:每处理一个字符 i++ |
sign | int | 定义:正负号(+1 / -1) 维护:只在符号位设置一次 更新:遇到 '-' 置 -1,'+' 置 +1 |
num | int | 定义:目前累积的数字(绝对值) 维护:每读一位 num = num*10 + 该位 更新:累积后立即用 sign*num 判断是否越界并截断 |
落码步骤
1. i = 0,跳过所有前导空格
2. 若当前是 '+'/'-',记录 sign 并 i++
3. 循环读数字:num = num*10 + (c - '0')
4. 每步判断 sign*num 是否 ≤ INT_MIN 或 ≥ INT_MAX,越界返回边界
5. 返回 sign * num
代码实现
class Solution:
def myAtoi(self, s: str) -> int:
INT_MIN, INT_MAX = -2**31, 2**31 - 1
i, n = 0, len(s)
while i < n and s[i] == ' ': # 1. 跳过前导空格
i += 1
sign = 1
if i < n and s[i] in '+-': # 2. 处理符号
sign = -1 if s[i] == '-' else 1
i += 1
num = 0
while i < n and s[i].isdigit(): # 3. 逐位累积
num = num * 10 + int(s[i])
i += 1
if sign * num <= INT_MIN: # 4. 提前判溢出并截断
return INT_MIN
if sign * num >= INT_MAX:
return INT_MAX
return sign * num
class Solution {
public:
int myAtoi(string s) {
int i = 0, n = s.size();
while (i < n && s[i] == ' ') i++; // 1. 跳过空格
int sign = 1;
if (i < n && (s[i] == '+' || s[i] == '-')) {
sign = (s[i] == '-') ? -1 : 1; // 2. 符号
i++;
}
long num = 0; // 用 long 累积防溢出
while (i < n && isdigit(s[i])) {
num = num * 10 + (s[i] - '0'); // 3. 累积
i++;
if (sign * num <= INT_MIN) return INT_MIN; // 4. 截断
if (sign * num >= INT_MAX) return INT_MAX;
}
return (int)(sign * num);
}
};
// 时间 O(n),空间 O(1)
复杂度分析
时间复杂度
O(n)
空间复杂度
O(1)
常见坑
前导空格只在最开头跳;数字中间或之后的空格意味着结束。
符号最多一个,"+-2" 这类第二个符号即非法,停止读取。
边累积边判溢出并截断到 INT_MIN/INT_MAX,不要等全部读完再判。
必测边界 Case
Case 1:仅空格
s = " " → 0
Case 2:正溢出
s = "91283472332" → 2147483647
Case 3:符号后无数字
s = "+" → 0