LeetCode高频题7:整数反转,除运算,取模运算的魅力
提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目
互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!
你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题
题目
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−2^31, 2**31 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/reverse-integer
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
一、审题
示例 1:
输入:x = 123
输出:321
示例 2:
输入:x = -123
输出:-321
示例 3:
输入:x = 120
输出:21
示例 4:
输入:x = 0
输出:0
暴力解:不可取
将x转化为字符串,然后用栈逆序,就是reverse操作
这个很难控制判断它是否越界,你还得设置try catch(exception e),这既耗费空间,也浪费时间,还不熟悉try操作,麻烦,代码有兴趣你可以看
public int reverse(int x) {
boolean negtive = false;
if (x < 0) {
x = -x;
negtive = true;
}
String s = String.valueOf(x);
char[] str = s.toCharArray();
Stack<Character> stack = new Stack<>();
for (int i = 0; i < str.length; i++) {
stack.push(str[i]);
}
int index = 0;
while (!stack.isEmpty()){
str[index++] = stack.pop();
}
s = String.valueOf(str);
try {
return negtive ? -Integer.valueOf(s) : Integer.valueOf(s);
}catch (Exception e){
return 0;
}
}//纯属暴力啊
测试:
Solution solution = new Solution();
System.out.println(solution.reverse(1234567889));
0
不咋地:将数字转字符数组,逆序一半,用交换函数搞定,节约一半时间
//优化一下
public int reverse2(int x) {
boolean negtive = false;
if (x < 0) {
x = -x;
negtive = true;
}
String s = String.valueOf(x);
char[] str = s.toCharArray();
int n = str.length;
for (int i = 0; i < n / 2; i++) {
swap(str, i , n - 1 - i);
}
s = String.valueOf(str);
try {
return negtive ? -Integer.valueOf(s) : Integer.valueOf(s);
}catch (Exception e){
return 0;
}
}
public void swap(char[] arr, int i, int j){
char tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
测试
System.out.println(solution.reverse2(1234567889));
也是繁杂0
面试最优解:单纯一个正数如何反转?很简单
如果是一个正数的话,怎么反转,其实很简单的
x=2345
你想搞出5432
其实每一次你只需要把最低位拿出来放左边,然后抹掉x的最低位,循环干
2345=x
(1)获取最低位:x%10就是最低位,抹掉最低位x/10就行
(2)最开始令ans=0,则取x%10=5出来,ans=ans10+5=5,x=x/10=234
(3)然后将x的最低位取出来x%10=4,ans=ans10+4=54,x=x/10=23
(4)然后将x的最低位取出来x%10=3,ans=ans10+3=543,x=x/10=2
(5)然后将x的最低位取出来x%10=2,ans=ans10+2=5432,x=x/10=0,一旦x=0,停止
结果就是5432
注意,中途你发现ans如果越界了,干死返回0
这个咋判断呢?比如987654321,而Integer最大就是2的31次方-1
显然越界了
这么判断,你上面ans不是每次倒要想办法让ans×10+x%10吗?
咱们提前准备整数最大值先除10,先模10
m = Integer.MAX_VALUE / 10;
o = Integer.MAX_VALUE % 10
如果在ans×10+x%10之前,ans就大于m了,则待会ans×10 > m×10=Integer.MAX_VALUE ,这就是越界了!!!
或者,在ans×10+x%10之前,ans就等于m,且x%10>o了,则待会ans×10+x%10 > m×10+o=Integer.MAX_VALUE ,这越界!!!
这个判断很妙吧?
这是互联网大厂考题经常考的取余运算和除法抹掉最低位,几乎所有互联网大厂的第一题都是这种数字类型的题目
手撕代码问题不大:
//复习,纯正数怎么反转,直接就,
public int reverseNumReviewPositive(int x){
//直接拿着干
int ans = 0;//准备接受新的数
int m = Integer.MAX_VALUE / 10;
int o = Integer.MAX_VALUE % 10;//整数最大值
while (x != 0){
if (ans > m ||(ans == m && ans % 10 > 0)) return 0;//中途发现越界返回0
//扣除最低位数,放左边,就是乘10+地位
ans = ans * 10 + x % 10;
x /= 10;
}
return ans;
}
测试:
public static void test(){
Solution solution = new Solution();
System.out.println(solution.reverse3(1234567889));
System.out.println(solution.reverseNumReviewPositive(1234567889));
}
public static void main(String[] args) {
test();
}
0
0
如果是负数反转呢?
跟上面正数那很类似
咱们这样子搞
32 位的有符号整数的范围 [−2^31, 2**31 − 1]
我们干脆这么整,将所有正数全变负数,这个是行的,因为正数范围没有负数大,所以折反对称过去还能放下不会越界的
操作嘛,和正数一样操作,取最低位,不断×10+最低位,ans最终就是逆转的数,只不过符号是负数
是正数的,将符号去掉就行
比如:
其实每一次你只需要把最低位拿出来放左边,然后抹掉x的最低位,循环干
x=2345的话,先转负数:
-2345=x
(1)获取最低位:x%10就是最低位,抹掉最低位x/10就行
(2)最开始令ans=0,则取x%10=-5出来,ans=ans10-5=-5,x=x/10=-234
(3)然后将x的最低位取出来x%10=-4,ans=ans10-4=-54,x=x/10=-23
(4)然后将x的最低位取出来x%10=-3,ans=ans10-3=-543,x=x/10=-2
(5)然后将x的最低位取出来x%10=-2,ans=ans10-2=-5432,x=x/10=0,一旦x=0,停止
结果就是-5432
最后将-号去掉,就是5432
当然中途判越界和整数几乎一幕一样
只不过,咱们判断的是小于关系
这么判断,你上面ans不是每次倒要想办法让ans×10+x%10吗?
咱们提前准备整数最小值先除10,先模10
m = Integer.MIN_VALUE / 10;
o = Integer.MIN_VALUE % 10
【注意是MIN哦】
如果在ans×10+x%10之前,ans就小于m了,则待会ans×10 < m×10=Integer.MIN_VALUE ,这就是越界了!!!
或者,在ans×10+x%10之前,ans就等于m,且x%10<o了,则待会ans×10+x%10 < m×10+o=Integer.MIN_VALUE ,这越界!!!
这个判断很妙吧?
和正数那如出一辙,只不过方向是负方向,得取小于关系
手撕代码:
//复习,负数怎么反转,直接就,
public int reverseNumReviewNegtive(int x){
//看看是正数的话,需要转
boolean isPostiveNum = x > 0 ? true : false;//标记是正数
x = x > 0 ? -x : x;//是正数先加个负号
//直接拿着干
int ans = 0;//准备接受新的数
int m = Integer.MIN_VALUE / 10;
int o = Integer.MIN_VALUE % 10;//整数最大值
while (x != 0){
if (ans < m ||(ans == m && ans % 10 < 0)) return 0;//中途发现越界返回0
//扣除最低位数,放左边,就是乘10+地位
ans = ans * 10 + x % 10;
x /= 10;
}
return isPostiveNum ? -ans : ans;//最后要去掉
}
你可以对照看看两个代码,十足骚!
测试一把:
public static void test(){
Solution solution = new Solution();
System.out.println(solution.reverse3(1234567889));
System.out.println(solution.reverseNumReviewPositive(1234567889));
System.out.println(solution.reverseNumReviewNegtive(1234567889));
System.out.println(solution.reverseNumReviewNegtive(12889));
System.out.println(solution.reverseNumReviewNegtive(-12889));
}
public static void main(String[] args) {
test();
}
0
0
0
98821
-98821
问题不大
还有一种骚操作:一律按取x最低位不断×10,x抹掉最低位,最后才判越界,用long!=int来算
就是最开始你就把ans令成long类型,64位长度
long ans=0
long类型是一定不会越界的!
最后你看看逆转之后ans转int之后,看看是否还等于原ans
如果还是相等的,说明压根没越界
如果越界,转int根本就是不等的
//继续优化一下
public int reverse3(int x) {
//很牛逼的做法
//123
//拿余数
long n = 0;
while (x != 0){
n = 10 * n + x % 10;//拿之前的n*10 + x最后一个数
x /= 10;//每次去一个数
}
//判断这里如果int的n==long的n,显然不会越界,返回n,否则就是0,牛逼
return (int) n == n ? (int) n : 0;
}
测试一把:
System.out.println(solution.reverse3(1234567889));
结果OK:0
怎么样?刷LeetCode,这个题看起来简单,实际上不简单的吧?各种操作,取余,除法抹掉最低位,判断数字是否越界?
总结
提示:重要经验:
1)逆转可以用栈,可以数组交换前后位置,可以通过加法取最低位不断逆转,x除10是抹掉最低位,x除10取余是取最低位,
2)判断整数越界与否?可以通过long转int,看看还相等与否?还可以控制最大值最小值/10=m,%10=o,然后看看ans×10+x%10之前,是否ans已经小于或者大于m,相等的话,看看x%10是否已经小于或者大于o了,是就越界,很巧妙的。
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。