请你来实现一个 myAtoi(string s)
函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi
函数)。
函数 myAtoi(string s)
的算法如下:
读入字符串并丢弃无用的前导空格
检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
将前面步骤读入的这些数字转换为整数(即,”123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0
。必要时更改符号(从步骤 2 开始)。
如果整数数超过 32 位有符号整数范围 [−231, 231 − 1]
,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231
的整数应该被固定为 −231
,大于 231 − 1
的整数应该被固定为 231 − 1
。
返回整数作为最终结果。
注意:
本题中的空白字符只包括空格字符 ' '
。
除前导空格或数字后的其余字符串外, 请勿忽略 任何其他字符。
示例 1:
**输入:** s = "42"
**输出:** 42
**解释:** 加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
第 1 步:"42"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
^
第 3 步:" _42_ "(读入 "42")
^
解析得到整数 42 。
由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。
示例 2:
**输入:** s = " -42"
**输出:** -42
**解释:**
第 1 步:" _ ****_ -42"(读入前导空格,但忽视掉)
^
第 2 步:" _**-**_ 42"(读入 '-' 字符,所以结果应该是负数)
^
第 3 步:" _**-42**_ "(读入 "42")
^
解析得到整数 -42 。
由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。
示例 3:
**输入:** s = "4193 with words"
**输出:** 4193
**解释:**
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
^
第 3 步:" _4193_ with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
^
解析得到整数 4193 。
由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。
提示:
0 <= s.length <= 200
s
由英文字母(大写和小写)、数字(0-9
)、' '
、'+'
、'-'
和 '.'
组成
视频题解 简述 根据问题的描述我们来判断并且描述对应的解题方法。对于这道题目,很明显是字符串的转化问题。需要明确转化规则,尽量根据转化规则编写对应的子函数。
这里我们要进行模式识别,一旦涉及整数的运算,我们需要注意溢出。本题可能产生溢出的步骤在于推入、乘以 $10$ 操作和累加操作都可能造成溢出。对于溢出的处理方式通常可以转换为 INT_MAX
的逆操作。比如判断某数乘以 $10$ 是否会溢出,那么就把该数和 INT_MAX
除以 $10$ 进行比较。
文字题解 方法一:自动机 思路
字符串处理的题目往往涉及复杂的流程以及条件情况,如果直接上手写程序,一不小心就会写出极其臃肿的代码。
因此,为了有条理地分析每个输入字符的处理方法,我们可以使用自动机这个概念:
我们的程序在每个时刻有一个状态 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
时,更新我们输入的数字,即可最终得到输入的数字。
[sol1-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 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' ], } def get_col (self, c ): if c.isspace(): return 0 if c == '+' or c == '-' : return 1 if c.isdigit(): return 2 return 3 def get (self, c ): self.state = self.table[self.state][self.get_col(c)] if self.state == 'in_number' : self.ans = self.ans * 10 + int (c) self.ans = min (self.ans, INT_MAX) if self.sign == 1 else min (self.ans, -INT_MIN) elif self.state == 'signed' : self.sign = 1 if c == '+' else -1 class Solution : def myAtoi (self, str : str ) -> int : automaton = Automaton() for c in str : automaton.get(c) return automaton.sign * automaton.ans
[sol1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 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; } };
[sol1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class Solution { public int myAtoi (String str) { Automaton automaton = new Automaton (); int length = str.length(); for (int i = 0 ; i < length; ++i) { automaton.get(str.charAt(i)); } return (int ) (automaton.sign * automaton.ans); } } class Automaton { public int sign = 1 ; public long ans = 0 ; private String state = "start" ; private Map<String, String[]> table = new HashMap <String, String[]>() {{ put("start" , new String []{"start" , "signed" , "in_number" , "end" }); put("signed" , new String []{"end" , "end" , "in_number" , "end" }); put("in_number" , new String []{"end" , "end" , "in_number" , "end" }); put("end" , new String []{"end" , "end" , "end" , "end" }); }}; public void get (char c) { state = table.get(state)[get_col(c)]; if ("in_number" .equals(state)) { ans = ans * 10 + c - '0' ; ans = sign == 1 ? Math.min(ans, (long ) Integer.MAX_VALUE) : Math.min(ans, -(long ) Integer.MIN_VALUE); } else if ("signed" .equals(state)) { sign = c == '+' ? 1 : -1 ; } } private int get_col (char c) { if (c == ' ' ) { return 0 ; } if (c == '+' || c == '-' ) { return 1 ; } if (Character.isDigit(c)) { return 2 ; } return 3 ; } }
复杂度分析