当前位置: 首页 > news >正文

LeetCode 8. 字符串转换整数 (atoi)

LeetCode 8. 字符串转换整数 (atoi) 解析

这个问题要求将字符串转换为 32 位有符号整数,需要处理前导空格、符号位、数字字符以及溢出情况。以下是详细解析:

方法思路

  1. 去除前导空格
    从字符串开头跳过所有空格字符。

  2. 处理符号位
    检查第一个非空格字符是否为 +-,确定结果的符号。

  3. 转换数字字符
    从符号位之后开始,连续读取数字字符(0-9)并转换为整数。遇到非数字字符时停止。

  4. 溢出处理
    在转换过程中检查是否溢出 32 位有符号整数的范围([-2^31, 2^31-1])。

C++ 代码实现

#include <string>
#include <climits>class Solution {
public:int myAtoi(string s) {int i = 0;int n = s.length();// 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. 转换数字并处理溢出int res = 0;while (i < n && isdigit(s[i])) {int digit = s[i] - '0';// 检查溢出:res * 10 + digit > INT_MAXif (res > (INT_MAX - digit) / 10) {return (sign == 1) ? INT_MAX : INT_MIN;}res = res * 10 + digit;i++;}return sign * res;}
};

代码解释

  1. 跳过前导空格
    使用 while 循环将指针 i 移动到第一个非空格字符位置。

  2. 处理符号位

    • 若遇到 +,符号为正;若遇到 -,符号为负。
    • 指针 i 后移一位,跳过符号字符。
  3. 转换数字并处理溢出

    • 遍历后续字符,若为数字(isdigit(s[i])),则转换为整数。
    • 溢出检查:在累加前检查是否会导致溢出。若 res * 10 + digit > INT_MAX,则根据符号返回 INT_MAXINT_MIN
  4. 返回结果
    将累加结果乘以符号位,得到最终转换结果。

复杂度分析

  • 时间复杂度:O(n),其中 n 是字符串长度。只需遍历一次字符串。
  • 空间复杂度:O(1),只需要常数级额外空间。

示例

情况1:正常转换

输入:s = " -42"
输出:-42
解释

  • 跳过前导空格后,遇到符号 -,符号位设为 -1
  • 后续数字字符为 42,转换为整数 42,乘以符号位得到 -42
情况2:溢出处理

输入:s = "2147483648"(即 2^31
输出:2147483647(即 INT_MAX
解释

  • 转换过程中检测到溢出(214748364 * 10 + 8 > INT_MAX),直接返回 INT_MAX
情况3:包含非数字字符

输入:s = "4193 with words"
输出:4193
解释

  • 遇到非数字字符 ' ' 时停止转换,返回已转换的部分 4193

关键点

  1. 溢出检查
    使用 res > (INT_MAX - digit) / 10 代替直接比较 res * 10 + digit > INT_MAX,避免整数溢出。

  2. 提前终止
    一旦遇到非数字字符,立即停止转换,避免无效处理。

  3. 符号位处理
    符号位仅在第一个非空格字符处生效,其他位置的符号字符会被视为非数字字符而终止转换。

这种方法通过线性扫描和边界检查,高效且安全地完成字符串到整数的转换。

方法二:

#include <string>
#include <climits>
#include <unordered_map>class Automaton {
private:std::string state = "start";std::unordered_map<std::string, std::vector<std::string>> table = {{"start", {"start", "signed", "in_number", "end"}},{"signed", {"end", "end", "in_number", "end"}},{"in_number", {"end", "end", "in_number", "end"}},{"end", {"end", "end", "end", "end"}}};// 获取字符类型对应的列索引int get_col(char c) {if (isspace(c)) return 0;if (c == '+' || c == '-') return 1;if (isdigit(c)) return 2;return 3;}public:int sign = 1;long long ans = 0;void get(char c) {state = table[state][get_col(c)];if (state == "signed") {sign = (c == '+') ? 1 : -1;} else if (state == "in_number") {ans = ans * 10 + (c - '0');// 处理溢出ans = (sign == 1) ? std::min(ans, (long long)INT_MAX) : std::min(ans, -(long long)INT_MIN);}}
};class Solution {
public:int myAtoi(string s) {Automaton automaton;for (char c : s) {automaton.get(c);if (automaton.state == "end") break;}return automaton.sign * automaton.ans;}
};

自动机(有限状态机)原理详解

自动机(Finite State Machine, FSM)是一种抽象计算模型,它由一组状态和状态之间的转移规则组成。在字符串处理中,自动机特别适合处理需要根据输入字符序列按特定规则转换状态的问题。

一、基本概念

1. 核心组件
  • 状态集合:自动机所有可能的状态。例如,LeetCode 8 中的 {start, signed, in_number, end}
  • 输入字符集:所有可能的输入字符。例如,{' ', '+', '-', '0'-'9', 其他字符}
  • 转移函数:定义状态之间的转换规则。例如,在状态 start 下遇到空格,转移到 start 状态。
  • 初始状态:自动机的起始状态。例如,start
  • 终止状态:自动机处理结束的状态。例如,end
2. 工作流程
  1. 从初始状态开始。
  2. 按顺序读取输入字符,根据当前状态和输入字符,通过转移函数切换到下一状态。
  3. 重复步骤 2,直到处理完所有输入或进入终止状态。

二、LeetCode 8 的自动机设计

1. 状态定义
  • start:初始状态,尚未处理任何有效字符。
  • signed:已处理符号位(+-)。
  • in_number:正在处理数字字符。
  • end:遇到非法字符或处理完毕,终止处理。
2. 转移规则

用表格表示状态转移函数:

当前状态\输入字符空格(’ ')符号(+/-)数字(0-9)其他字符
startstartsignedin_numberend
signedendendin_numberend
in_numberendendin_numberend
endendendendend
3. 状态转移图
start ──(空格)──→ start├──(符号)──→ signed└──(数字)──→ in_number└──(其他)──→ endsigned ──(数字)──→ in_number└──(其他)──→ endin_number ──(数字)──→ in_number└──(其他)──→ endend ──(任何)──→ end

三、自动机的实现逻辑

1. 状态转移表的代码表示
std::unordered_map<std::string, std::vector<std::string>> table = {{"start", {"start", "signed", "in_number", "end"}},{"signed", {"end", "end", "in_number", "end"}},{"in_number", {"end", "end", "in_number", "end"}},{"end", {"end", "end", "end", "end"}}
};
  • :当前状态。
  • :输入字符类型(空格、符号、数字、其他)。
  • :下一个状态。
2. 输入字符分类
int get_col(char c) {if (isspace(c)) return 0;        // 空格if (c == '+' || c == '-') return 1;  // 符号if (isdigit(c)) return 2;        // 数字return 3;                        // 其他
}
3. 状态更新逻辑
void get(char c) {state = table[state][get_col(c)];  // 根据当前状态和输入字符更新状态if (state == "signed") {sign = (c == '+') ? 1 : -1;    // 记录符号位} else if (state == "in_number") {ans = ans * 10 + (c - '0');    // 累加数字// 处理溢出ans = (sign == 1) ? std::min(ans, (long long)INT_MAX) : std::min(ans, -(long long)INT_MIN);}
}

四、自动机处理示例

输入" -42"
  1. 初始状态start
  2. 处理字符
    • ' '(空格):start → start,保持初始状态。
    • ' '(空格):start → start
    • ' '(空格):start → start
    • '-'(符号):start → signed,记录符号位 -1
    • '4'(数字):signed → in_number,累加数字 4
    • '2'(数字):in_number → in_number,累加数字 4*10 + 2 = 42
  3. 结果sign * ans = -1 * 42 = -42

五、自动机的优势

  1. 逻辑清晰
    将复杂的条件判断转化为明确的状态转移表,避免嵌套的 if-else 语句,提高代码可读性。

  2. 可维护性强
    当需求变化时(如增加新的状态或转移规则),只需修改转移表,无需大规模重构代码。

  3. 完整性
    自动机强制覆盖所有可能的状态和输入组合,减少遗漏边界条件的风险。

  4. 扩展性
    容易扩展到更复杂的字符串处理问题,如词法分析、语法解析等。

六、应用场景

自动机广泛应用于:

  • 字符串匹配(如正则表达式引擎)
  • 编译原理(词法分析、语法分析)
  • 网络协议解析
  • 游戏状态管理
  • 人工智能中的行为决策

在处理具有明确状态转换规则的问题时,自动机是一种强大且优雅的解决方案。

方法三:

class Solution {
public:int myAtoi(string s) {stringstream ss(s);int n;ss >> n;return n;}
};
http://www.dtcms.com/a/273249.html

相关文章:

  • 【保姆级喂饭教程】idea中安装Conventional Commit插件
  • FreeRTOS—任务创建和删除的API函数和方法
  • 书生实训营第二关:大模型对战
  • 列表初始化
  • C++ Lambda 表达式详解
  • 《棒垒球知道》奥运会的吉祥物是什么·棒球1号位
  • 【c++八股文】Day6:using和typedef
  • [yolo-world]YOLO-World数据集介绍及标注格式详解
  • SoC程序如何使用单例模式运行
  • 什么是 MIT License?核心要点解析
  • [数据结构与算法] 优先队列 | 最小堆 C++
  • 几种LLM推理加速技术的区别
  • 列表页与详情页的智能识别:多维度判定方法与工业级实现
  • 海光芯赋能:国产化高性能计算平台,重塑边缘与工业智能新算力
  • 使用虚拟机远程登陆ensp模拟器交换机
  • ROS1学习第二弹
  • 1 C++提高——模板
  • H5微应用四端调试工具—网页版:深入解析与使用指南
  • FS-TAS如何提升电催化反应的效率-测试GO
  • 人大金仓下载安装教程总结
  • 区块链基础知识:从比特币到区块链的全面解析
  • 复杂度简介
  • Android-jetpack之DataBinding实战应用
  • NMEA-0183 协议 GPS 介绍
  • Redis-集群Cluster
  • Python练习(1)Python基础类型操作语法实战:20道实战题解与案例分析(上)
  • 《一起出发,“春”不“晚”》特别行动踏梦武当,探寻新春奇境
  • 教育领域AI教师培训计划及相关行业动态的综合简报
  • CVPR2022——RepLKNet模型有效感受野的热图可视化
  • Java Stream流:高效数据处理全解析