【C++算法打怪专栏】8. 字符串转换整数 (atoi)
1. 题目描述
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数。
处理规则:
- 前导空格: 读入字符串并丢弃无用的前导空格
' '。 - 正负号: 检查下一个字符为
'-'还是'+'(若都不存在,默认为正)。 - 转换数字: 跳过前置零并读取连续数字,直到遇到非数字字符或到达字符串结尾。
- 范围截断: 若结果超过 32 位有符号整数范围 INT_MIN,INT_MAXINT\\_MIN, INT\\_MAXINT_MIN,INT_MAX(即 −231,231−1-2\^{31}, 2\^{31} - 1−231,231−1),则截断返回对应的边界值。
2. 核心避坑点分析
编写该题时,容易出现以下几类逻辑错误:
- 条件判断错误:
s[i] != '-' || s[i] != '+'属于逻辑恒真条件(字符不可能同时是两个不同符号),会导致分支控制失效。 - 数字字符比较误区:
s[i] >= 0 && s[i] <= 9比较的是 ASCII 码 0~9 的控制字符,正确写法应为'0' <= s[i] && s[i] <= '9'或使用std::isdigit()。 - 索引越界与跳过: 若初始指针直接从
1开始,当首字符就是合法数字时会导致漏读第一个数字。 - 数据溢出问题: 未提前判断累加过程中的数值溢出,可能导致
int越界产生未定义行为。
3. 解题思路与步骤
采用单指针扫描法,按顺序完成以下三步:
- 清除前置空格: 使用指针
i跳过开头的连续空格。 - 提取符号: 检查当前字符是否为正负号,用变量
sign(1或-1)标记正负,同时指针自增。 - 按位累加并检查溢出:
- 逐位读取数字字符并计算
res = res * 10 + (s[i] - '0')。 - 溢出处理: 在每一步计算后(或累加前)检查
sign * res是否超出INT_MAX/INT_MIN范围,若超出则立即返回边界值。
- 逐位读取数字字符并计算
4. C++ 代码实现
cpp
#include <string>
#include <climits>
class Solution {
public:
int myAtoi(std::string s) {
int i = 0;
int n = s.size();
// 1. 忽略前导空格
while (i < n && s[i] == ' ') {
i++;
}
// 2. 处理正负号
int sign = 1;
if (i < n && (s[i] == '+' || s[i] == '-')) {
sign = (s[i] == '-') ? -1 : 1;
i++;
}
// 3. 转换数字并实时判断溢出
long long res = 0; // 使用 long long 防止累加过程中 int 直接溢出
while (i < n && s[i] >= '0' && s[i] <= '9') {
int digit = s[i] - '0';
res = res * 10 + digit;
// 检查 32 位有符号整数边界
if (sign * res >= INT_MAX) return INT_MAX;
if (sign * res <= INT_MIN) return INT_MIN;
i++;
}
return static_cast<int>(sign * res);
}
};
5. 复杂度分析
- 时间复杂度: O(N)O(N)O(N),其中 NNN 是字符串
s的长度,只需对字符串进行一次单向遍历。 - 空间复杂度: O(1)O(1)O(1),仅使用了常数级的额外空间。