力扣字符串转换整数C++题解

class Automaton {

    string state = "start";

    unordered_map<string, vector<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 == '+' or 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 == "in_number") {

            ans = ans * 10 + c - '0';

            ans = sign == 1 ? min(ans, (long long)INT_MAX) : min(ans, -(long long)INT_MIN);

        }

        else if (state == "signed")

            sign = c == '+' ? 1 : -1;

    }

};

class Solution {

public:

    int myAtoi(string str) {

        Automaton automaton;

        for (char c : str)

            automaton.get(c);

        return automaton.sign * automaton.ans;

    }

};

这段 C++ 代码实现了将字符串转换为整数(atoi 函数的功能),不过是通过自定义的有限自动机(Automaton)的思路来处理输入字符串,按照一定的规则解析出合法的整数部分,并考虑了正负号、数值范围等情况,最终在 Solution 类的 myAtoi 函数中返回转换后的整数值。

Automaton 类解析

成员变量部分
string state = "start";
unordered_map<string, vector<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 sign = 1;
long long ans = 0;

state:表示自动机当前所处的状态,初始化为 "start",它会随着对输入字符串字符的处理而按照规则转换到不同的状态。

table:这是一个无序映射(unordered_map),用于定义状态转移规则。它的键是状态名称(如 "start""signed" 等),值是一个字符串向量,表示在当前键对应的状态下,接收到不同类型的输入字符后要转移到的下一个状态。例如,在 "start" 状态下,当接收到空格(对应列索引为 0,后面 get_col 函数会解释如何对应)时转移到 "start" 状态,接收到 '+' 或 '-'(对应列索引为 1)时转移到 "signed" 状态,接收到数字(对应列索引为 2)时转移到 "in_number" 状态,接收到其他非法字符(对应列索引为 3)时转移到 "end" 状态。

sign:用于记录最终解析出的整数的符号,初始化为 1,表示正数,当遇到负号时会被修改为 -1

ans:用于累加解析出的数字部分,初始化为 0,它是一个 long long 类型,以便在处理过程中可以暂时容纳较大的数值,最后再根据范围和符号等情况转换为合适的 int 类型返回。

get_col 函数
int get_col(char c) {
    if (isspace(c)) return 0;
    if (c == '+' or c == '-') return 1;
    if (isdigit(c)) return 2;
    return 3;
}

这个函数的作用是根据输入的字符 c 判断它属于哪一类输入,然后返回对应的列索引(用于在 table 中查找状态转移的目标状态)。具体来说:

如果字符 c 是空格(通过 isspace 函数判断),返回 0,意味着对应 table 中状态转移表的第 0 列情况。

如果字符 c 是 '+' 或者 '-'(通过直接比较判断),返回 1,对应状态转移表的第 1 列。

如果字符 c 是数字(通过 isdigit 函数判断),返回 2,对应第 2 列,用于处理数字部分的状态转移。

如果字符 c 不属于上述几种情况,也就是其他非法字符,返回 3,对应转移到 "end" 状态,表示解析应该结束了。

get 函数

void get(char c) {
    state = table[state][get_col(c)];
    if (state == "in_number") {
        ans = ans * 10 + c - '0';
        ans = sign == 1? min(ans, (long long)INT_MAX) : min(ans, -(long long)INT_MIN);
    }
    else if (state == "signed")
        sign = c == '+'? 1 : -1;
}

这个函数用于处理输入字符串中的单个字符,按照有限自动机的规则更新状态并处理相应情况:

首先,通过 table[state][get_col(c)] 根据当前的状态 state 和输入字符 c 对应的列索引(由 get_col 函数获取)来查找并更新自动机的状态。

接着,如果更新后的状态是 "in_number",说明当前正在处理数字部分,就将当前字符对应的数字累加到 ans 中(通过 ans = ans * 10 + c - '0'; 实现,即将之前积累的数字乘以 10 再加上当前数字字符对应的整数值)。然后,为了避免数值溢出,通过 min 函数结合符号 sign 来确保 ans 的值在 int 类型所能表示的范围之内。如果 sign 为 1(正数),就将 ans 和 INT_MAX 比较取较小值;如果 sign 为 -1(负数),就将 ans 和 -(long long)INT_MIN 比较取较小值。这样可以防止最终结果超出 int 类型的范围。

如果更新后的状态是 "signed",说明刚刚遇到了正负号,根据字符 c 是 '+' 还是 '-' 来设置 sign 的值,'+' 时 sign 设为 1'-' 时设为 -1

Solution 类解析

myAtoi 函数

int myAtoi(string str) {
    Automaton automaton;
    for (char c : str)
        automaton.get(c);
    return automaton.sign * automaton.ans;
}

这个函数是对外提供的接口,用于将输入的字符串 str 转换为整数。具体步骤如下:

首先创建一个 Automaton 类的对象 automaton,这个对象会按照其内部定义的有限自动机规则来处理输入字符串。

然后通过一个范围 for 循环遍历输入字符串中的每个字符,并调用 automaton 对象的 get 函数来处理每个字符,在这个过程中,自动机的状态、符号以及数字部分的累加值等都会根据规则逐步更新。

最后,返回 automaton.sign * automaton.ans,也就是根据解析出的符号和数字部分组合成最终的整数结果返回。

总的来说,这段代码利用有限自动机的思想巧妙且严谨地实现了字符串到整数的转换功能,充分考虑了各种边界情况,比如正负号处理、非法字符处理以及数值溢出等问题,相比于简单直接的实现方式在逻辑完整性和健壮性方面表现更好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值