878. 第 N 个神奇数字 数学+二分

878. 第 N 个神奇数字

一个正整数如果能被 a 或 b 整除,那么它是神奇的。

给定三个整数 n , a , b ,返回第 n 个神奇的数字。因为答案可能很大,所以返回答案 对 109 + 7 取模 后的值。

示例 1:

输入:n = 1, a = 2, b = 3
输出:2

示例 2:

输入:n = 4, a = 2, b = 3
输出:6

提示:

  • 1 <= n <= 10^9
  • 2 <= a, b <= 4 * 10^4

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/nth-magical-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

做题结果

成功 

方法:数学+二分

1. 求最大公约数

2. 每到达一次最大公约数,就是 从 a 到达的次数+从 b 到达次数 - lcm 次数

3. 那大概就在上一个公倍数,到下一个公倍数之间,比如 6,2,3 ,2和3最小公倍数是6,那每到达6就经过 3 个 2 的倍数 和 2 个 3 的倍数,其中 6 是公共的,减掉 1个,那每经过 6,就消耗掉 4 个数,所以可以确定,n=6 是经过了 1 个 最小公倍数周期,也就是 n/4*6=6,也就是大概在 6 到 12之间,可在这部分二分拿到答案。

class Solution {
    public int nthMagicalNumber(int n, int a, int b) {
        long lcm = lcm(a,b);
        long time = lcm/a+lcm/b-1;
        long left = n/time*lcm;
        long right = (n/time+1)*lcm;
        while(left<right){
            long mid = (right-left)/2+left;
            long cnt = mid/a+mid/b-mid/lcm;
            if(cnt<n){
                left = mid+1;
            }else{
                right = mid;
            }
        }
        return (int) (right%(long)(1e9+7));
    }

    private long lcm(long a, long b){
        long gcd = gcd(a,b);
        return a/gcd*b/gcd*gcd;
    }

    private long gcd(long a, long b){
        return b== 0?a:gcd(b,a%b);
    }
}

时间复杂度:O(log(max(a,b)))

空间复杂度:O(1)

其他,如果a,b 较小, n 足够大(中间计算超过long)的情况下,怎么处理呢?

可考虑记录一个周期,而非直接计算次数,前面的部分,可直接计算到公倍数求余的和,最后一部分可先缩减到第一个周期计算,然后再补充前面的余数再求余。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值