以下是我直接写的代码,就很无脑,想着先把前面可能出错的情况写出来,在判断数字出错的情况写出来,基本上很多细节想不到,都是在LeetCode上提交发现的。
细节太多,容易报空指针和数组越界异常,还有最无脑的就是算术异常,具体如何写出来的已经写在上面的code中。
/**
● 函数myAtoi(string s) 的算法如下:
●
● 读入字符串并丢弃无用的前导空格
● 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
● 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
● 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
● 如果整数数超过 32 位有符号整数范围 [−2^31, 2^31− 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 2^31− 1 的整数应该被固定为 2^31− 1 。
● 返回整数作为最终结果。
● 注意:
●
● 本题中的空白字符只包括空格字符 ' ' 。
● 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
●
● 输入:s = "4193 with words"
● 输出:4193
● 解释:
● 第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
● ^
● 第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
● ^
● 第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
● ^
● 解析得到整数 4193 。
● 由于 "4193" 在范围 [-2^31, 2^31 - 1] 内,最终结果为 4193 。
●
● //也就是说第一位要么+ / -
● //后面的是数字,继续加,不是数字 则返回零
● //不是数字,break
*/
class Solution {
public int myAtoi(String s) {
//读懂题意很重要,这个myAtoi,就是先判断第一个是什么符号,如果什么符号都没有,就是正的,如果不是数字也不是+ — 符号,则说明数字为零
//而且此函数返回整形,小数点后面的也不用看了
//先转成StringBuilder 对象,防止用String 占用内存空间,s.trim()顺便把前后空格删除
StringBuilder sBuilder = new StringBuilder(s.trim());
//用 i 来搞sBuilder的charAt()方法,获取字符串,特意做成一
int i = 1;
//判断正负
int d = 0;
//来截取长度
int begin = 0;
int distance = 0;
//防止全是空格的情况<细节>
if (sBuilder.toString().equals("")) return 0;
//判断第一个符号是正还是负
if (sBuilder.charAt(0) == '-') d++;
//判断第一个是否为数字
else if (sBuilder.charAt(0) >= '0' && sBuilder.charAt(0) <= '9') {
begin++;//长度加一<细节>
} else if (sBuilder.charAt(0) == '+') d = d;//这个好像只能这么搞了,去掉不行, 会跳到下一步<细节> +1返回零了
else if (!(sBuilder.charAt(0) >= '0' && sBuilder.charAt(0) <= '9')) return 0;//如果第一个不是 + - (上面的条件不满足)或者 数字,直接返回零
if(sBuilder.charAt(0) == '0' || sBuilder.charAt(0) == '+' || sBuilder.charAt(0) == '-') {
//如果第一个满足上面条件,进入循环,保证数字不从0开始,Eg:000000002000000000<细节>
//因为从零在下面也算长度 begin++
while (i < sBuilder.length()) {//<细节>如果用sBuilder.charAt(i) == '0'直接判断,可能长度为1,下标就为零,空指针异常
if (sBuilder.charAt(i) == '0') {
i++;
} else {
break;
}
}
}
while (i < sBuilder.length()) {//遇到数组的时候,先判断长度!!!!!
if ('0' <= sBuilder.charAt(i) && sBuilder.charAt(i) <= '9') {
begin++;//计算长度
distance = i;//记录数字截至的地方的后一位
i++;
} else {
break;
}
}
//如果 长度 长度没有增加,说明 i 在第一个循环到了 末尾都是零 ,所以直接返回零<细节>
if(begin == 0 && distance == 0) return 0;
//如果 i 为 1 ,而且第一个为 — 或者 +,说明字符串里面只有 正 或者 负 符号<细节>
if (i == 1 && (sBuilder.charAt(0) == '-' || sBuilder.charAt(0) == '+')) return 0;
if (i > 0) {
//如果begin的长度大于10,肯定大于max 或者 min<细节>,不然长度太大,连long都放不下了
if (d == 1 && begin > 10) return Integer.MIN_VALUE;
if (d == 0 && begin > 10) return Integer.MAX_VALUE;
//截取长度
long myAtoi = Long.parseLong(sBuilder.substring(distance - begin + 1, distance + 1));
//判断正负
if (d == 1) myAtoi = -myAtoi;
//满足题意,判断范围
if (myAtoi <= Integer.MAX_VALUE && myAtoi >= Integer.MIN_VALUE) {
return (int) myAtoi;
} else if (myAtoi <= Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
} else {
return Integer.MAX_VALUE;
}
}
//这个没办法,写着满足语法
return 0;
}
}
献丑了,呜呜呜~~~
接下来是我学习到的大佬的代码
class Solution {
public int myAtoi(String str) {
str = str.trim();
if (str.length() == 0) return 0;
if (!Character.isDigit(str.charAt(0))//判断下标为 零 是否为数字 + / -,是就跳出if语句
&& str.charAt(0) != '-' && str.charAt(0) != '+')
return 0;
long ans = 0L;//这样才好与边界值比较
boolean neg = str.charAt(0) == '-';//等于,为true
int i = !Character.isDigit(str.charAt(0)) ? 1 : 0;//判断从哪个下标开始 记数,是数字,从零下标计数
while (i < str.length() && Character.isDigit(str.charAt(i))) {//判断是否为数字,并且防止数组越界
ans = ans * 10 + (str.charAt(i++) - '0');//ans存的是正数
if (!neg && ans > Integer.MAX_VALUE) {//正数越界情况 eg:-123
ans = Integer.MAX_VALUE;
break;
}
if (neg && ans > 1L + Integer.MAX_VALUE) {//负数越界情况,所以要加一
ans = 1L + Integer.MAX_VALUE;
break;
}
}
return neg ? (int) -ans : (int) ans;//负数返回负数,正数返回负数
}
}
Character.isDigit(str.charAt(i)); 这个东东就很巧妙,用于判断数字,就不用 0<= x <= 9
boolean neg = str.charAt(0) == '-'; 这个写法就很巧妙,的返回true or false
int i = !Character.isDigit(str.charAt(0)) ? 1 : 0; 这个也很巧妙,判断从什么地方开始
while (i < str.length() && Character.isDigit(str.charAt(i))) 虽然这里用了,charAt(i) 方法,但是前面限制了长度条件,防止空指针报错,数组越界,就很巧妙