leetcode 1201.丑数 III

本文详细解析了LeetCode上“丑数III”问题的两种解决方案:暴力法和二分求交集法。介绍了如何利用辗转相除法计算最小公倍数,以及如何运用二分法在1到2e9范围内高效寻找第n个至少能被a、b或c整除的正整数。

原题如下

https://leetcode-cn.com/problems/ugly-number-iii/
在这里插入图片描述

题解

首先注意审题,题目说的是,可以被 a 或 b 或 c 整除的 正整数,只要至少被abc之一整除即可。

方法一 暴力

暴力法也就是从1开始判断,一个数是不是至少能被三个数之一整除,直到找到第n个为止。这样的方法效率极低,而且只能通过3个示例。

class Solution {
    public int nthUglyNumber(int n, int a, int b, int c) {
        int i=0;
        int ans=1;
        while(i<n){
            if(ans%a==0||ans%b==0||ans%c==0){
                i++;
            }
            ans++;
        }return ans-1;
    }
}
//3 / 50 个通过测试用例  状态:超出时间限制
//最后执行的输入:1000000000  2  217983653  336916467

方法二 二分求交集法

说到用求交集的方法,因为对于某个比较大的数,我们需要首先找到在小于这个数的范围内,有多少能被a、b或者c整除的的数字也就是能被三个数整除的数的集合取个并集。对于有交集的三个集合取总并集,有这个公式,A∪B∪C=A+B+C-A∩B-B∩C-A∩C+A∩B∩C。而一个数同时可以被两个数整除,那就等价于能被俩数的最大公约数整除,能被三个数整除等价于能被三个数的最小公倍数整除,因此我们先用辗转相除法计算出abc两两的以及三个数的最小公倍数。进而可以通过这些求出某数范围内能至少被abc一个数整除的数的个数。
说用二分法,是因为题目说答案的最大可能也就是2e9,那么我们再1到2e9之间通过二分逐渐缩小范围算出最小的数,在不大于这个数的范围内有n个丑数
本思路java代码示例:

/*
 *@v7fgg
 *执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
 *内存消耗 :36.1 MB, 在所有 Java 提交中击败了20.00%的用户
 *2020年6月14日 20:03
 */
class Solution {
    public int nthUglyNumber(int n, int a, int b, int c){
        long ab=zuixiaogongbei((long)a,(long)b);
        long bc=zuixiaogongbei((long)b,(long)c);
        long ac=zuixiaogongbei((long)a,(long)c);
        long abc=zuixiaogongbei(ab,(long)c);
        //二分法
        long zuo=1;
        long you=2000000000;                
        while(zuo<you){
            long mid=zuo+(you-zuo)/2;
            long p=mid/a+mid/b+mid/c-mid/ab-mid/ac-mid/bc+mid/abc;
            if(p>n){
                you=mid-1;                
            }
            else if(p<n){
                zuo=mid+1;
            }
            else{you=mid;}         
        }return (int)zuo;
    }
    public long zuixiaogongbei(long m,long n){
        //求m和n的最小公倍数
        long max=Math.max(m,n);
        long min=m+n-max;
        if(m>1&&n>1&&m!=n){            
            while(max%min!=0){                
                long yu=max%min;
                max=min;
                min=yu;
            }
            //上面最终的除数是最大公约数,最小公倍数等于乘积除以最大公约数
            return m*n/min;       
        }return (long)Math.max(m,n);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

可爱抱抱呀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值