LeetCode高频题7:整数反转,除运算,取模运算的魅力

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=ans
10+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=ans
10+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=ans
10-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=ans
10-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,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰露可乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值