请你来实现一个 atoi
函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。
提示:
‘ ‘
。
示例 1:
输入: "42" 输出: 42
示例 2:
输入: " -42" 输出: -42 解释: 第一个非空白字符为 ‘-‘, 它是一个负号。 我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: "4193 with words" 输出: 4193 解释: 转换截止于数字 ‘3‘ ,因为它的下一个字符不为数字。
示例 4:
输入: "words and 987" 输出: 0 解释: 第一个非空字符是 ‘w‘, 但它不是数字或正、负号。 因此无法执行有效的转换。
示例 5:
输入: "-91283472332" 输出: -2147483648 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 因此返回 INT_MIN (?231) 。
思路
字符串处理的题目往往涉及复杂的流程以及条件情况,如果直接上手写程序,一不小心就会写出极其臃肿的代码。
因此,为了有条理地分析每个输入字符的处理方法,我们可以使用自动机这个概念:
我们的程序在每个时刻有一个状态 s
,每次从序列中输入一个字符 c
,并根据字符 c
转移到下一个状态 s‘
。这样,我们只需要建立一个覆盖所有情况的从 s
与 c
映射到 s‘
的表格即可解决题目中的问题。
算法
本题可以建立如下图所示的自动机:
我们也可以用下面的表格来表示这个自动机:
‘ ‘ | +/- | number | other | |
---|---|---|---|---|
start | start | signed | in_number | end |
signed | end | end | in_number | end |
in_number | end | end | in_number | end |
end | end | end | end | end |
接下来编程部分就非常简单了:我们只需要把上面这个状态转换表抄进代码即可。
另外自动机也需要记录当前已经输入的数字,只要在 s‘
为 in_number
时,更新我们输入的数字,即可最终得到输入的数字。
INT_MAX = 2 ** 31 - 1
INT_MIN = -2 ** 31
class Automaton:
def init(self):
self.state = ‘start‘
self.sign = 1
self.ans = 0
self.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‘],
}
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_col</span><span class="hljs-params">(self, c)</span>:</span>
<span class="hljs-keyword">if</span> c.isspace():
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>
<span class="hljs-keyword">if</span> c == <span class="hljs-string">‘+‘</span> <span class="hljs-keyword">or</span> c == <span class="hljs-string">‘-‘</span>:
<span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
<span class="hljs-keyword">if</span> c.isdigit():
<span class="hljs-keyword">return</span> <span class="hljs-number">2</span>
<span class="hljs-keyword">return</span> <span class="hljs-number">3</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self, c)</span>:</span>
self.state = self.table[self.state][self.get_col(c)]
<span class="hljs-keyword">if</span> self.state == <span class="hljs-string">‘in_number‘</span>:
self.ans = self.ans * <span class="hljs-number">10</span> + int(c)
self.ans = min(self.ans, INT_MAX) <span class="hljs-keyword">if</span> self.sign == <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> min(self.ans, -INT_MIN)
<span class="hljs-keyword">elif</span> self.state == <span class="hljs-string">‘signed‘</span>:
self.sign = <span class="hljs-number">1</span> <span class="hljs-keyword">if</span> c == <span class="hljs-string">‘+‘</span> <span class="hljs-keyword">else</span> <span class="hljs-number">-1</span>
class Solution:
def myAtoi(self, str: str) -> int:
automaton = Automaton()
for c in str:
automaton.get(c)
return automaton.sign * automaton.ans
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"}}
};
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">get_col</span><span class="hljs-params">(<span class="hljs-keyword">char</span> c)</span> </span>{
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">isspace</span>(c)) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
<span class="hljs-keyword">if</span> (c == <span class="hljs-string">‘+‘</span> <span class="hljs-keyword">or</span> c == <span class="hljs-string">‘-‘</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">isdigit</span>(c)) <span class="hljs-keyword">return</span> <span class="hljs-number">2</span>;
<span class="hljs-keyword">return</span> <span class="hljs-number">3</span>;
}
public:
int sign = 1;
long long ans = 0;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">get</span><span class="hljs-params">(<span class="hljs-keyword">char</span> c)</span> </span>{
state = table[state][get_col(c)];
<span class="hljs-keyword">if</span> (state == <span class="hljs-string">"in_number"</span>) {
ans = ans * <span class="hljs-number">10</span> + c - <span class="hljs-string">‘0‘</span>;
ans = sign == <span class="hljs-number">1</span> ? min(ans, (<span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>)INT_MAX) : min(ans, -(<span class="hljs-keyword">long</span> <span class="hljs-keyword">long</span>)INT_MIN);
}
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (state == <span class="hljs-string">"signed"</span>)
sign = c == <span class="hljs-string">‘+‘</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">-1</span>;
}
};
class Solution {
public:
int myAtoi(string str) {
Automaton automaton;
for (char c : str)
automaton.get(c);
return automaton.sign * automaton.ans;
}
};
复杂度分析
时间复杂度:,其中 为字符串的长度。我们只需要依次处理所有的字符,处理每个字符需要的时间为 。
空间复杂度:,自动机的状态只需要常数空间存储。
原文:https://www.cnblogs.com/leetcodetijie/p/13049838.html