LeetCode8 字符串转换整数 Atoi
题目地址:https://leetcode-cn.com/problems/reverse-integer/
题目难度:中等
请你来实现一个atoi函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;
假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−2^31, 2^31 − 1]。如果数值超过这个范围,
请返回 INT_MAX (2^31 − 1) 或 INT_MIN (−2^31) 。
示例
示例1:
输入: " -42"
输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例2:
输入: "-91283472332"
输出: -2147483648
解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 因此返回 INT_MIN (−2^31) 。
示例3:
输入: "4193 with words"
输出: 4193
解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例 4:
输入: "words and 987"
输出: 0
解释: 第一个非空字符是 'w', 但它不是数字或正、负号,因此无法执行有效的转换。
分析
这道题主要是特殊情况比较多,将这些特殊情况都考虑一下就能通过。在做这道题目的时候我正在搞正则表达式方面的东西,所以进行是否合格判断通过正则匹配进行的,但是我写的正则耗时挺大的,导致效率不会很高。要提升效率首先得细微上找寻耗时的逻辑代码,若是没有更大的效果,则需要换种思路来解决问题。其实这道题最开始我就掉到自己挖的坑里了,正则表达式处理这种匹配是要更方便些,但同时也增加了耗时。
解答1 正则表达式
public int myAtoi(String str) {
String number = "0";
int index = 0;
for (int i = 1; i <= str.length(); i++) {
if (number == "0"){
String s = str.substring(0, i);
index = i - 2 >= 0 ? i - 2 : 0;
number = isValid(s) ? str.substring(index, i) : "0";
if (i == str.length()) {
return getValidInt(number);
}
continue;
} else {
number = str.substring(index, i);
}
if (!number.matches("\\s?[+-]?\\d*")) {
number = number.substring(0, i - 1 - index).trim();
return getValidInt(number);
} else if (i == str.length() && number.matches("\\s?[+-]?\\d*")) {
number = str.trim();
return getValidInt(number);
}
}
return 0;
}
private Boolean isValid(String s) {
if (s.matches(".*\\d")) {
if (s.matches("\\s*[+-]?\\d")) {
return true;
} else {
return false;
}
}
return false;
}
private int getValidInt(String number) {
int num;
try {
num = Integer.parseInt(number);
} catch (NumberFormatException e) {
if (number.contains("-")) {
num = Integer.MIN_VALUE;
} else {
num = Integer.MAX_VALUE;
}
}
return num;
}
耗时75 ms,击败5.08%的提交记录
解答2
public int myAtoi1(String str) {
int length = str.length();
int i = 0;
int end = 0;
int start = 0;
Boolean status = false;
while (i < length) {
String match = str.substring(0, i + 1);
if (match.matches("\\s*[+-]?\\d")){
start = i - 1 >= 0 ? i - 1 : 0;
status = true;
}
if (i == length - 1 && match.matches("\\s*[+-]?\\d*") && status) {
end = length;
}
if (!match.matches("\\s*[+-]?\\d*") && status) {
end = i;
break;
}
i++;
}
if (!status) {
return 0;
}
String number = str.substring(start, end).trim();
return getValidInt(number);
}
这种方法也是通过正则表达式进行的匹配,但是得到对应的字符串是通过记录开始截取和截止截取的位置,然后通过截取和去空完成的
耗时90m,相对来说和上一个效果差不多,没有实质性优化效果
解答3 非正则解法
public int myAtoi2(String str) {
int length = str.length();
//符号状态
boolean status = true;
//是否已经开始
boolean start = true;
StringBuilder s = new StringBuilder();
for (int i = 0; i < length; i++) {
char temp = str.charAt(i);
if ((temp >= 48 && temp <= 57)) {
start = false;
s.append(temp);
} else if (start && (temp == '-' || temp == '+')) {
status = temp == '+';
start = false;
} else if (start && temp == ' ') {
continue;
} else {
break;
}
}
int y = 0;
for (int i = 0; i < s.length(); i++) {
int x = s.charAt(i) - 48;
if (status) {
if ((y == Integer.MAX_VALUE / 10 && x > 7) || y > Integer.MAX_VALUE / 10) {
return Integer.MAX_VALUE;
}
y = y * 10 + x;
} else {
if ((y == Integer.MIN_VALUE / 10 && x > 8) || y < Integer.MIN_VALUE / 10) {
return Integer.MIN_VALUE;
}
y = y * 10 - x;
}
}
return y;
}
耗时 8ms 击败86.43%提交记录
在写这篇博客的时候我发现这个程序耗时太长,于是就研究了一下,发现可以通过两个布尔值规约得出只含有数字的字符串,然后剩下的就是将字符串转换成整形数字了,我最开始写了Integer.parseInt方法,然后超出范围时会报错,然后我看了一下这个方法的源码,于是结合上一道题的思路,最终完美的将这道题解决,很有成就感。
相似题目
有效数字
总结
解决一个问题时,选择不同的方法带来的效果会有很大的差异,这就需要庞大的积累才能在关键时刻及时的判断出最合适的方法,然后经过一些细节微调就能完美的解决问题。这道题给我很大的触动,自己还需要积攒更多的知识,革命尚未成功,同志们仍需努力。