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
,也就是根据解析出的符号和数字部分组合成最终的整数结果返回。
总的来说,这段代码利用有限自动机的思想巧妙且严谨地实现了字符串到整数的转换功能,充分考虑了各种边界情况,比如正负号处理、非法字符处理以及数值溢出等问题,相比于简单直接的实现方式在逻辑完整性和健壮性方面表现更好。