题目链接
请你来实现一个 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:
示例2:
示例3:
1 2 输入:s = "4193 with words" 输出:4193
示例4:
1 2 输入:s = "words and 987" 输出:0
示例5:
1 2 输入:s = "-91283472332" 输出:-2147483648
方法一 首先识别出字符串中的数字,并记录其正负。从低位到高位,对于每一个字符 c,用 c - ‘0’ 得到实际数字值,对于所有数字累加:ans = ans*10 + c-'0'
,ans 是 int 类型,需要注意溢出问题。ans*10
会溢出,ans*10 + c-‘0’也会溢出。判断方法:
1 2 3 4 5 6 int num = c-'0' ;if (ans > INT_MAX/10 || (ans==INT_MAX && num>7 )){ }else { ans = ans*10 + c-'0' }
代码如下:
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 46 47 48 49 50 51 52 53 54 55 56 57 58 class Solution {public : int myAtoi (string s) { int first = 0 ; int last = 0 ; bool ispositive = false ; int ans = 0 ; for (; first<s.length (); ++first){ if (s[first]!=' ' ) break ; } if (s[first]=='-' ){ ispositive=true ; ++first; }else if (s[first]=='+' ){ ++first; } if (s[first]<'0' || s[first]>'9' ){ return 0 ; } for (; first<s.length (); ++first){ if (s[first]!='0' ) break ; } for (int i=first; i<s.length (); ++i){ if (s[i]<'0' || s[i]>'9' ){ break ; }else { last = i; } } for (int i=first; i<=last; ++i){ int num = s[i]-'0' ; if (ans > INT_MAX/10 || (ans==INT_MAX/10 && num>7 )) return ispositive?INT_MIN:INT_MAX; else ans = ans*10 + num; } if (ispositive){ return -ans; }else { return ans; } } };
可以看到代码容易写的比较臃肿,接下来介绍自动机方法。
方法二 自动机法。本方法使用的自动机,也叫有限状态自动机,它包含多种状态,有开始状态,也有结束状态,一个状态可以跳转到其他状态。从开始状态开始,经过状态的改变来到结束状态。
使用自动机:可以识别特定的符号,当然它也可以在字符串中识别数字。
如下图所示自动机:
start 表示开始状态,end 表示结束状态
start 表示开始状态,开始状态遇到 ‘空格’ 还是start 状态(相当于去掉前导0);遇到数字,就跳转到 in_number 状态;遇到+/-号,就跳转到 signed;遇到其他字符就进入 end 状态(表示无数字)。
signed 遇到数字,进入 in_number(开始处理数字),遇到其它非数字符号,就进入 end 状态。
in_number 遇到数字还是 in_number;遇到其它字符,说明已经处理完数字,直接进入 end 。
代码如下:
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 class Automata { 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=='+' ||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 s) { Automata automata; for (char c:s){ automata.get (c); } return automata.sign * automata.ans; } };
上述代码使用自动机扫描字符串,并识别其中的数字和正负号。代码中使用 long long 类型,它是 64 位系统独有的,不适用于 32 位系统。为了提高兼容性,接下来给出 适用于 32 位系统的版本。
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 46 47 48 49 50 51 52 53 class Automata { 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=='+' ||c=='-' ) return 1 ; if (isdigit (c)) return 2 ; return 3 ; } public : int sign = 1 ; int ans = 0 ; bool finish = true ; void get (char c) { state = table[state][get_col (c)]; if (state=="in_number" ){ int num = c-'0' ; if (ans > INT_MAX/10 || (ans==INT_MAX/10 && num>7 )){ ans = sign==1 ?INT_MAX:INT_MIN; finish = false ; }else if (finish==true ){ ans = ans*10 + num; } }else if (state == "signed" ){ sign = c=='+' ?1 :-1 ; } } }; class Solution {public : int myAtoi (string s) { Automata automata; for (char c:s){ automata.get (c); } if (automata.finish) return automata.ans * automata.sign; else return automata.ans; } };