LeetCode刷题记录——08字符串转换整数
一 题目描述:
该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转换规则:
- 如果第一个非空字符为正或者是为负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号的整数
- 假如第一个非空字符是数字,则直接将其与之后的连续的数字字符组合起来,形成一个整数
- 该字符串在有效的整数部分之后也可能存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响
【注意】假如字符串中的第一个非空格字符不是一个有效的整数字符、字符串为空或者字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效的转换。在任何情况下,若函数不能有效地转换时,返回0
-
例子:
-
输入:"4193 with words" 输出: 4193 输入: "words and 987" 输出: 0
二 思路:
-
-
自动机
-
对于每一个字符,都有一个对应的状态,因此我们就建立一个相应的状态表格就ok,这被叫做DFA?(之后查资料补上)
-
’ ’ +/- 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 -
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; } };
-
这种DFA的方式,得到的结果正确,但是效率不如下面的位运算高
-
-
利用位运算处理
-
关键在于转换中防止超过最大值以及求int的最大值,
-
第一点可以使用,res*10 + curVal <= Max,
-
第二点,可以考虑位运算,直接左移31位,但是直接左移31位会影响符号,所以三步走
- 先将1 左移30位,然后减去1,此时二进制为:0011111111111111111111111111(两个0和30个1)
- 左移一位,,此时二进制为:0111111111111111111111111110,
- 然后加一
-
class Solution { public: int myAtoi(string str) { const char *p = str.c_str(); //part1:判断-/+的位置(如果有的话) for(; p != nullptr && *p == ' '; p++) {} if(p == nullptr || (*p != '+' && *p != '-' && (*p < '0' || *p > '9'))) { return 0; } //part2:确定整数的符号 int res = 0, flag = 1; if(*p == '-') { flag = -1; p++; } else if(*p == '+') { p++; } //part3:转换,字符to整数,并进行越界判断 int MAX = (((1 << 30)-1)<<1) + 1;//利用左移求得最大值 int MIN = -MAX-1; for(; '0' <= *p && *p <= '9'; p++) { if((MAX-(*p-'0')) / 10 < res) { if(flag == -1) { return MIN; } else { return MAX; } } (res *= 10) += *p-'0'; } return res * flag; } };
-