剑指Offer:字符串转整数的实现与边界处理

B站影视 日本电影 2025-09-02 21:31 1

摘要:在编程面试中,“字符串转换成整数”是一道经典题目,它不仅考察基础的字符串遍历能力,更侧重对边界条件和异常场景的处理。本文将结合问题分析、思路拆解与多语言实现,带你掌握这道题的核心考点,避免常见陷阱。

在编程面试中,“字符串转换成整数”是一道经典题目,它不仅考察基础的字符串遍历能力,更侧重对边界条件和异常场景的处理。本文将结合问题分析、思路拆解与多语言实现,带你掌握这道题的核心考点,避免常见陷阱。

将一个字符串转换成整数,禁止使用语言自带的字符串转整数库函数(如 C++ 的 atoi、Python 的 int);若输入为非法数值或空字符串,返回 0;若为合法数值(含正负号),返回对应整数。

输入 输出 说明 "+2147483647" 2147483647 合法正数,返回对应数值 "1a33" 0 含非数字字符,非法输入 "-123" -123 合法负数,返回对应数值 ""(空串) 0 空输入,返回 0

这道题的关键不在于“转换”本身,而在于异常处理与边界控制。在实现前,必须明确以下 5 个需要处理的场景:

空值判断:输入字符串为空("")或指针为空(C++ 场景);正负号处理:字符串开头可能包含 + 或 -,需标记符号并跳过符号位;非法字符过滤:遍历中遇到非数字字符(如 a、!),直接判定为非法,返回 0;整数溢出检查:32 位整数的取值范围是 [-2^31, 2^31 - 1](即 -2147483648 到 2147483647),超出范围需返回 0;结果区分:需区分“合法的 0”(如输入 "0")和“非法的 0”(如输入 "abc"),避免混淆。

基于上述考点,我们可以将转换过程拆分为 4 个核心步骤,确保每一步覆盖对应的边界场景:

符号标记:用 minus 布尔值标记是否为负数(默认 false,即正数);结果存储:用 long long(C++)或 int(Python,因 Python 整数无溢出,但需手动判断范围)存储中间结果,避免转换过程中溢出;状态标记:用 g_nStatus(C++)或类似变量区分“合法结果”与“非法结果”,避免将 0 误判。若字符串首字符为 +:标记符号为正数,指针/索引向后移动一位;若字符串首字符为 -:标记符号为负数,指针/索引向后移动一位;若首字符为数字:直接进入后续遍历;若首字符为其他字符(如 a、 ):直接返回 0。对每个字符,先判断是否为数字(>= '0' 且 若是数字:计算当前结果 = 上一轮结果 × 10 + 符号 × (当前字符 - '0')('0' 的 ASCII 码为 48,通过差值获取数字值);若不是数字:立即将结果置为 0,跳出循环(判定为非法输入)。每次计算后检查溢出:正数场景:若结果 > 2147483647(即 0x7fffffff),置为 0 并跳出;负数场景:若结果 #include using namespace std;class Solution {public:// 状态枚举:区分合法结果(kValid)与非法结果(kInValid)enum Status { kValid = 0, kInValid };// 全局状态变量,外部可通过此变量判断结果是否合法int g_nStatus = kValid;int StrToInt(string str) {g_nStatus = kInValid; // 初始默认非法,避免合法0与非法0混淆long long num = 0; // 用long long存储中间结果,防止溢出const char* cstr = str.c_str; // 转为C风格字符串,便于指针操作// 第一步:判断指针非空且字符串非空if (cstr != nullptr && *cstr != '\0') {bool minus = false; // 符号标记:false为正,true为负// 第二步:处理正负号if (*cstr == '+') {cstr++; // 跳过'+',指针后移} else if (*cstr == '-') {minus = true; // 标记为负数cstr++; // 跳过'-',指针后移}// 第三步:若符号后仍有字符,进入核心转换if (*cstr != '\0') {num = StrToIntCore(cstr, minus);}}return static_cast(num); // 强制转为int返回}private:// 核心转换函数:处理数字部分,判断溢出long long StrToIntCore(const char* cstr, bool minus) {long long num = 0;while (*cstr != '\0') {// 检查当前字符是否为数字if (*cstr >= '0' && *cstr 2^31 - 1(0x7fffffff)// 负数溢出:num 0x7fffffff) || (minus && num (0x80000000))) {num = 0; // 溢出则置为0break;}cstr++; // 指针后移,处理下一个字符} else {// 遇到非数字字符,置为0并跳出num = 0;break;}}// 若遍历正常结束(指针指向'\0'),标记为合法状态if (*cstr == '\0') {g_nStatus = kValid;}return num;}};**状态变量 g_nStatus**:解决“合法 0”与“非法 0”的区分问题,例如输入 "0" 时 g_nStatus = kValid,输入 "abc" 时 g_nStatus = kInValid;long long 类型:由于 32 位 int 的最大值为 2147483647,若用 int 存储中间结果,计算 214748364 * 10 + 7 时可能溢出,因此用 long long 暂存;溢出判断:通过十六进制常量 0x7fffffff(2147483647)和 0x80000000(-2147483648)直接判断,避免手动计算幂次出错。

Python 的整数无固定长度,理论上不会溢出,但需手动判断是否超出 32 位整数范围;同时 Python 字符串处理更简洁,无需指针操作:

# -*- coding:utf-8 -*-class Solution:def StrToInt(self, s):s = s.strip # 可选:去除字符串前后空格(如输入" -123")length = len(s)if length == 0:return 0 # 空字符串,返回0minus = False # 符号标记:False为正,True为负start_idx = 0 # 数字部分的起始索引# 处理正负号if s[0] == '+':start_idx = 1 # 跳过'+',从索引1开始遍历elif s[0] == '-':minus = True # 标记为负数start_idx = 1 # 跳过'-',从索引1开始遍历num = 0sign = -1 if minus else 1 # 符号系数:-1为负,1为正# 遍历数字部分for char in s[start_idx:]:# 检查是否为数字if '0' 2**31 - 1 or num strip 处理:可选步骤,若题目允许输入包含前后空格(如 " +2147"),可先去除空格,增强鲁棒性;ord 函数:通过 ord(char) - ord('0') 将字符数字转为整数(如 ord('5') - ord('0') = 5);溢出判断:直接用 2**31 - 1(2147483647)和 -2**31(-2147483648)判断,符合 Python 语法习惯。支持更多场景:若题目允许输入包含前导零(如 "00123"),当前代码已兼容,无需额外处理;异常抛出:若需要更明确的错误提示,可将“非法输入”改为抛出异常(如 ValueError),而非仅返回 0;性能优化:C++ 中可直接用 string 遍历(无需转为 C 风格字符串),减少指针操作的复杂度。

“字符串转整数”看似简单,实则是对“代码鲁棒性”的全面考察。核心思路是“先处理边界,再逐字符转换,全程检查异常”

边界处理:空值、符号位、非法字符;转换逻辑:利用“结果 × 10 + 当前数字”实现逐位累加;溢出控制:根据 32 位整数范围实时判断,避免结果超出限制。

掌握这道题的解题思路,不仅能应对面试,更能培养“考虑所有异常场景”的编程思维,为复杂问题的解决打下基础。

来源:码农世界

相关推荐