# 878. Nth Magical Number

**<font color=red>难度: Hard</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/nth-magical-number/description/

> 内容描述

```
A positive integer is magical if it is divisible by either A or B.

Return the N-th magical number.  Since the answer may be very large, return it modulo 10^9 + 7.

 

Example 1:

Input: N = 1, A = 2, B = 3
Output: 2
Example 2:

Input: N = 4, A = 2, B = 3
Output: 6
Example 3:

Input: N = 5, A = 2, B = 4
Output: 10
Example 4:

Input: N = 3, A = 6, B = 4
Output: 8
 

Note:

1 <= N <= 10^9
2 <= A <= 40000
2 <= B <= 40000
```

## 解题方案

> 思路 1
******- 时间复杂度: O(A+B)******- 空间复杂度: O(1)******

数学题直接看的[solution](https://leetcode.com/problems/nth-magical-number/solution/)：

* 从数据范围看来，N高达10^9，直接遍历不现实
* 注意到魔法数是有循环的，我们令P=A和B的最小公倍数，那么在每P个数中，魔法数的数量和位置都是相同的，因此我们只需要计算[1,p]中间的魔法数
* [1,p]的魔法数数量是 P/A+P/B-1，注意到，P是A和B的最小公倍数，因此[1,p]中，既能被A整除，也能被B整除，只有一个数，就是P
* 现在问题变成，在[1,p]中，求第n个魔法数

注意到，我们在[1,p]中任取一个数x（x<p），[1,x]中魔法数的数量是x/A+x/B，注意这个是整除。

```python
class Solution(object):
    def nthMagicalNumber(self, N, A, B):
        """
        :type N: int
        :type A: int
        :type B: int
        :rtype: int
        """
        def gcd(a, b):
            if b == 0:
                return a
            return gcd(b, a % b)
        
        def lcm(a, b):
            return a * b // gcd(a, b)
        
        MOD = 10**9 + 7

        L = lcm(A, B)
        M = L // A + L // B - 1
        q, r = divmod(N, M)

        if r == 0:
            return q * L % MOD

        heads = [A, B]
        for _ in range(r - 1):
            if heads[0] <= heads[1]:
                heads[0] += A
            else:
                heads[1] += B

        return (q * L + min(heads)) % MOD
```


> 思路 2
******- 时间复杂度: O(log(N*max(A,B)))******- 空间复杂度: O(1)******


从另外一个角度来看，如果我们知道了一个数字x，那么我们可以轻易算出有多少个magic number 是小于等于x的，
即```x // A + x // B - x // L```, 其中```L = lcm(A, B)```, 我们可以通过二分法算出一个最小的数字num，小于等于num的magic number 数量刚好是N,
然后这个num就是我们要求的 Nth Magical Number

时间复杂度为O(log(N∗max(A,B))), beats 100%

```python
class Solution(object):
    def nthMagicalNumber(self, N, A, B):
        """
        :type N: int
        :type A: int
        :type B: int
        :rtype: int
        """
        def gcd(a, b):
            if b == 0:
                return a
            return gcd(b, a % b)
        
        def lcm(a, b):
            return a * b // gcd(a, b)
        
        MOD = 10**9 + 7
        L = lcm(A, B)

        def magic_below_x(x):
            # How many magical numbers are <= x?
            return x // A + x // B - x // L

        l, r = 0, N * max(A,B)
        while l <= r:
            mid = l + ((r-l) >> 1)
            if magic_below_x(mid) < N:
                l = mid + 1
            else:
                r = mid - 1

        return l % MOD
```

