leetcode 878. 第 N 个神奇数字(java)

第 N 个神奇数字

  • leetcode 878. 第 N 个神奇数字
    • 题目描述
    • 二分 + 容斥
    • 代码演示
    • 上期算法

leetcode 878. 第 N 个神奇数字

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/nth-magical-number

题目描述

一个正整数如果能被 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 <= 109
2 <= a, b <= 4 * 104

二分 + 容斥

思路与算法
题目给出三个数字 n,a,b,满足 1≤n≤1e9,2≤a,b≤4×1e4,并给出「神奇数字」的定义:若一个正整数能被 a 和 b 整除,那么它就是「神奇」的。现在需要求出对于给定 a 和 b 的第 n 个「神奇数字」。设 f(x) 表示为小于等于 x 的「神奇数字」个数,因为小于等于 x 中能被 a 整除的数的个数为 (x / a),小于等于 x 中能被 b 整除的个数为 (x / b),小于等于 x 中同时能被 a 和 b 整除的个数为 (x / c),其中 c 为 a 和 b 的最小公倍数,所以 f(x) 的表达式为:
f(x)= (x / a) + (x / b) − (x / c);
即f(x) 是一个随着 x 递增单调不减函数。那么我们可以通过「二分查找」来进行查找第 n 个「神奇数字」。

代码演示

  /**
     * 最小公约数
     * @param a
     * @param b
     * @return
     */
    public int gcd(int a,int b){
        return b == 0 ? a : gcd(b,a % b);
    }

    /**
     * 最小公倍数
     * @param a
     * @param b
     * @return
     */
    public int lct(int a,int b){
        return  (a * b)/gcd(a,b);
    }

    /**
     * 神奇数字
     * @param n
     * @param a
     * @param b
     * @return
     */
    public int nthMagicalNumber(int n, int a, int b) {
        long l = Math.min(a,b);
        long r = n * l;
        //求出最小公倍数
        int c = lct(a,b);
        while (l <= r){
            long mid = (l + r)/2;
            long cnt = mid / a + mid / b - mid / c;
            if (cnt >= n){
                r = mid - 1;
            }else {
                l = mid + 1;
            }
        }
        return (int)((r + 1) % 1000000007);
    }

上期算法


力扣 1155. 掷骰子等于目标和的方法数(动态规划-java)

leetcode464. 我能赢吗

leetcode97. 交错字符串

leetcode583. 两个字符串的删除操作

leetcode72. 编辑距离

leetcode123. 买卖股票的最佳时机 III

你可能感兴趣的:(算法,数据结构,java,leetcode,java,算法,数据结构,贪心算法,动态规划)