目录
题目
解题思路
讲道理,这题的题目是真的长,但是题目是真的不难,就根据他的要求写,就能达标。真的不难,可能写起来稍微复杂一点,这次我还是想当的有自信的,给大家看看通过速度和内存占用。
然后我竟然发现了这个有个复杂度分析,还是想当准确的。
说实话其实想复杂也复杂不起来,就是遍历一遍字符数组,也就是遍历一遍字符串了。然后通过他的条件筛选一下,还是很简单的。那我们来讲讲思路。
首先我们可以看到他说要的事32位有符号整数,所以我们是正常的int即可,不需要unsigned(虽然java里也没有unsigned),但是又根据提示s.length范围是[0,200]从0到200然后是闭区间,所以这个需要在我们进行转换的时候要判断一下有没有超最大值。
接着看第一条要求,他说摒弃前导空格,我们可以用api也可以自己写,我选择自己写,还是相对底层一些。
第二条,检查是否有'-'和'+',那就是让我们看是否为正数还是负数,没有自然就是正数。
第三条,前置零,这玩意根本不影响,因为我们的思路是拿一个放进去一个,所以就是使用上了*=10进行十进制的位数左移,开头是零的话根本不影响。然后还有读不到数字即为0,这个案例也跟我们说明白了
第四条,超范围被固定位对应的最大值。
最后我们根据案例判断出里面没细讲的,正常检测数字的时候后面碰到非数字的字符直接结束转换(其实0-1也是属于这块,因为0是数字,末尾碰到了-不是数字直接结束转换)。
理清楚了之后呢我们可以直接开写。
解题代码
class Solution {
public int myAtoi(String str) {
long res = 0;
boolean first = true;
boolean isNegative = false;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if ((c == '-' || c == '+') && first || c >= '0' && c <= '9') {
if (first) {
first = false;
}
int num = c - '0';
if (num == -3) {
isNegative = true;
}
if (num >= 0) {
if (!isNegative && res * 10L > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
if (isNegative && res * -10L < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
res *= 10L;
res += num;
}
} else if (c == ' ' && first) {
continue;
} else {
break;
}
}
if (isNegative) {
res *= -1;
}
if (res > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
if (res < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
return (int) res;
}
}
我这里使用了两个布尔值进行判断,是否为负数以及是否为开头字符,也就是经过了+-之后那就是正常的数字判断了,然后我的一级判断是+-和0-9属于一级,无论是谁开头,我们都把开头字符置为false,然后再次碰到+或者是-的时候我们直接进入最后的else退出循环。
然后我们在两个判断之间塞入了是否为空格,自然也要判断是否为前导空格,如果不是则也是进入最后一个分支退出循环,如果是前导空格我们直接continue,虽然不写也一样,但是写上好看点IDE不会报黄虽然continue是灰色的。
第三步,我们就是判断是否为负数,当然这个放在外面来判断,然后我们在确定返回值虽然是int但是考虑一些情况我们就使用long来,也就从4字节变成了8字节,又不是数组所以还是比较省内存的。
第四步,我们看内部条件,首先是刚刚用到的无论走过什么开头,我们都把他置为false,以后碰到的开头可能出现的那些都是假开头。然后我们再将我们的0-9字符变成真正的数字,我们直接减去'0'即可,因为数字还是在ascii的128个字符范围内,我们可以直接减去他们最小的字符,就可以获得数字的0-9。
第五步,我们再看那个num==-3这个条件,实际上就是'-'-'0'的结果,也就是判断他为负号。这里是不会出现意外的,因为如果不是第一次进来的话我们,后续就不会再碰到了'-'号了,所以这里可以优化,可以把他放到判断开头的那个分支里面。也可以不用减直接判断是否为'-',然后就是又判断了一下num是否大于等于0,因为'+'-'0'=-5,防止开头碰到+号直接给他塞进去了个-5。
第六步,我们在里面判断是否满足在int范围内的情况,当然我们再做个保险,防止一些漏判,所以我们在最下面也放一个判断。里面的是可以防止那些范围很大或者超了long范围的,外面负责减一些钻了左移在下面的漏洞的,运算语句判断范围的上面容易误判。最后就是,我们的这个存的语句了,很简单,我们使用十进制往左移一位然后再加上的做法来存我们转换过的数字。
最后,返回我们计算出来的值即可。
官方解法
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;
}
}
速度是这样的。
有点慢了说实话,但是确实是一个好思路,因为不会被各种条件判断而打乱思路,条件并不是特别多,但是写起来比直接看题目出现的思路再写多太多了。并不是很推荐。
如果对你有帮助的话,不要忘记点赞收藏。