难度: Hard
原题连接
内容描述
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:
- 从数据范围看来,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,注意这个是整除。
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(Nmax(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%
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