返回介绍

solution / 0800-0899 / 0878.Nth Magical Number / README

发布于 2024-06-17 01:03:33 字数 3547 浏览 0 评论 0 收藏 0

878. 第 N 个神奇数字

English Version

题目描述

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

给定三个整数 na , 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

     

    解法

    方法一:数学 + 二分查找

    根据题目描述,神奇数字是能被 $a$ 或 $b$ 整除的正整数。

    而我们知道,对于任意正整数 $x$,在 $[1,..x]$ 范围内,能被 $a$ 整除的数有 $\lfloor \frac{x}{a} \rfloor$ 个,能被 $b$ 整除的数有 $\lfloor \frac{x}{b} \rfloor$ 个,能被 $a$ 和 $b$ 同时整除的数有 $\lfloor \frac{x}{c} \rfloor$ 个,其中 $c$ 是 $a$ 和 $b$ 的最小公倍数。最小公倍数的计算公式为 $c = lcm(a, b) = \frac{a \times b}{gcd(a, b)}$。

    因此,对于任意正整数 $x$,在 $[1,..x]$ 范围内,神奇数字的个数为:

    $$ \lfloor \frac{x}{a} \rfloor + \lfloor \frac{x}{b} \rfloor - \lfloor \frac{x}{c} \rfloor $$

    为什么要减去 $\lfloor \frac{x}{c} \rfloor$ 呢?可以这样理解,在 $[1,..x]$ 范围内,能被 $a$ 和 $b$ 同时整除的数,它们既能被 $a$ 整除,也能被 $b$ 整除,因此它们被计算了两次,需要减去一次。

    题目要我们找到第 $n$ 个神奇数字,也即是说,要找到一个最小的正整数 $x$,使得以下式子成立:

    $$ \lfloor \frac{x}{a} \rfloor + \lfloor \frac{x}{b} \rfloor - \lfloor \frac{x}{c} \rfloor \geq n $$

    随着 $x$ 的增大,神奇数字的个数也会增大,因此我们可以使用二分查找的方法,找到最小的正整数 $x$,使得上述式子成立。

    注意答案的取模操作。

    时间复杂度 $O(\log M)$,空间复杂度 $O(1)$。其中 $M$ 是二分查找的上界,本题可以取 $M=(a+b) \times n$。

    class Solution:
      def nthMagicalNumber(self, n: int, a: int, b: int) -> int:
        mod = 10**9 + 7
        c = lcm(a, b)
        r = (a + b) * n
        return bisect_left(range(r), x=n, key=lambda x: x // a + x // b - x // c) % mod
    
    class Solution {
      private static final int MOD = (int) 1e9 + 7;
    
      public int nthMagicalNumber(int n, int a, int b) {
        int c = a * b / gcd(a, b);
        long l = 0, r = (long) (a + b) * n;
        while (l < r) {
          long mid = l + r >>> 1;
          if (mid / a + mid / b - mid / c >= n) {
            r = mid;
          } else {
            l = mid + 1;
          }
        }
        return (int) (l % MOD);
      }
    
      private int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
      }
    }
    
    using ll = long long;
    
    class Solution {
    public:
      const int mod = 1e9 + 7;
    
      int nthMagicalNumber(int n, int a, int b) {
        int c = lcm(a, b);
        ll l = 0, r = 1ll * (a + b) * n;
        while (l < r) {
          ll mid = l + r >> 1;
          if (mid / a + mid / b - mid / c >= n)
            r = mid;
          else
            l = mid + 1;
        }
        return l % mod;
      }
    };
    
    func nthMagicalNumber(n int, a int, b int) int {
      c := a * b / gcd(a, b)
      const mod int = 1e9 + 7
      r := (a + b) * n
      return sort.Search(r, func(x int) bool { return x/a+x/b-x/c >= n }) % mod
    }
    
    func gcd(a, b int) int {
      if b == 0 {
        return a
      }
      return gcd(b, a%b)
    }
    

    如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

    扫码二维码加入Web技术交流群

    发布评论

    需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
    列表为空,暂无数据
      我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
      原文