1. 整数反转
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)
思想:
想法①
将数字转为字符串,然后将字符串反转接着转为整数,这样做有几个很难处理的点,例如将负数的处理,负号怎么处理、前置0怎么处理,不考虑溢出的话转为整数会去掉前置0、怎么判断溢出?当然字符串的反转这一块可以使用栈?
新思路:
对于整数x来说,使用x mod 10就可以将数x的末尾取出,使用x / 10 就可以将整数向后移动一位。例如65535,65535 mod 10 = 5将整数的最后一个数字取出了,65535 / 10 = 6553就将整数向后移动了一位,那么我们最终得到的数字为rev = rev * 10 + 余数,依次迭代下去便可得到结果,例如下过程:
x = 65535
第一次循环:x = 65535 digit = 5 rev = rev * 10 + digit = 5 x = 6553
第二次循环:x = 6553 digit = 3 rev = rev * 10 + digit = 53 x = 655
第三次循环:x = 655 digit = 5 rev = rev * 10 + digit = 553 x = 65
...依次直到x = 0
接着考虑负数问题,一位使用的是除法与取模对负数也是可以使用的,所以与整数合并;
接着考虑溢出问题,因为int类型的范围为[-2 ^ 31, 2 ^ 31 + 1],所以如果有数字2147483647要进行反转就变为了 7463847412那么就有溢出了,看了题解,题解的推导过程比较正式,可以使用一种简单的方法,例如:
对于溢出我只需要判断下一次的rev是否溢出即可,也就是说下一次循环 应该有 rev * 10 + x mod 10 > Integer.MAX_VALUE(这里只考虑一边)
也就是有 rev * 10 > Integer.MAX_VALUE - x mod 10
也就是有 rev > (Integer.MAX_VALUE - x mod 10 ) / 10
也就是有 rev > Integer.MAX_VALUE / 10 - (x mod 10) / 10,而很显然x mod 10 一定是小于10的然后在/10就为0了呗
最终得到溢出的判定条件:
Integer.MIN_VALUE / 10(对于负数来说一样的判定思路) <= rev <= Integer.MAX_VALUE / 10
class Solution {
public int reverse(int x) {
int rev = 0;
while(x != 0){
if(rev < (Integer.MIN_VALUE / 10) || rev > (Integer.MAX_VALUE / 10)) return 0;
int digit = x % 10;
x /= 10;
rev = rev * 10 + digit;
}
return rev;
}
}
其实也可以简单的理解为,如果当前的rev rev < (Integer.MIN_VALUE / 10)不成立,那么因为下一次rev = rev * 10 + digit,那么rev就一定会超过Integer.MIN_VALUE
当然,在面试中可以直接使用long进行扩大范围,然后强行向下转如果结果和之前一样,那么说明没有丢失精度,如果结果不一样则说明丢失精度则溢出了
2. 字符串转整数
请你来实现一个 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 。
- 返回整数作为最终结果
思想:
可以从题意上看出,本题需要注意的点有很多:
- 需要去掉字符串的前导空格
- 需要判断正负,可以使用一个变量当遇到负号或者正号时说明读取整数操作要从下一个字符开始
- 当读取整数的工作开始的时候遇到非数字即停止,可以使用一个变量标志读取工作是否开始
- 需要判断是否溢出,判断溢出和上面一题的思路相同,但是要注意的是因为上一题的输入本身就是int类型所以不会溢出,但是这题是直接字符串
举个例子说明,因为判定条件是res > (Integer.MAX_VALUE / 10) 当字符串为“2147483648”,当前的res为214748364的时候res == Integer.MAX_VALUE / 10这个时候还需要判定余数是否在0-7之间,因为最大值是2147483647,所以要额外的添加一个判断
class Solution {
public int myAtoi(String s) {
boolean flag = false;
int isfushu = 1;
int res = 0;
for(int i = 0;i < s.length();i++){
//去掉空格
if(s.charAt(i) == ' ' && !flag) continue;
//判断正负,无论正负从下一个字符开始,扫描整数的工作都要开始
if(!flag && (s.charAt(i) == '-' || s.charAt(i) == '+')){
if(s.charAt(i) == '-') isfushu = -1;
flag = true;
continue;
}
if(flag && ('0' > s.charAt(i) || '9' < s.charAt(i))) break;
if('0' <= s.charAt(i) && '9' >= s.charAt(i)){
flag = true;
//为正数 两个条件判断溢出
if( res > (Integer.MAX_VALUE / 10) || (res == (Integer.MAX_VALUE / 10) && ( s.charAt(i) - '0' > 7))){
return Integer.MAX_VALUE;
}
//为负数 同样也是两个条件判断溢出
if( res < (Integer.MIN_VALUE / 10) || (res == (Integer.MIN_VALUE / 10) && ( s.charAt(i) - '0' > 8))){
return Integer.MIN_VALUE;
}
res = res * 10 + isfushu * (s.charAt(i) - '0');
}
//没有遇到正负号
if(!flag) return 0;
}
return res;
}
}