题目:
这道题的题意是寻找一个数,这个数是第N个可以被A整除或者能被B整除的数,也就是寻找满足某些要求的某个数字,因此是比较典型的一道用二分的题。就还是二分的那几个步骤:
step1: 确定查找的上下界,这个数最小是0,最大的值这里可以就直接定为10^18,或者根据题意分析最大值不会超过N*max(A,B)。
step2: 确定check()函数,就是对于查找的某个数怎么判断它是否满足条件。这里对于当前查找的数mid,我们可以看小于它的可以被A或B整除的数是否有N个,若是没有的话说明这个数太小了,应该在[mid+1,hi]之间重新查找;若是当前查找的数mid前满足条件的数大于等于N个,说明我们需要找到的数还可以再更小一点,因此可以在[lo,mid]之间再次查找。如此往复,直到lo和hi相等,说明找到了最后我们想要的那个数。
代码如下:
class Solution:
def nthMagicalNumber(self, N: int, A: int, B: int) -> int:
mod = 10**9 + 7
lo, hi = 0, N*max(A,B) # z我们找的这个数肯定不会比N*max(A,B)更大了
# lo, hi = 0, 10**18 # 当不知道搜索的上界定为什么的时候也可以就直接用10^18
C = (A*B) // math.gcd(A, B) # 求A和B的最小公倍数,最小公倍数=两数乘积/两个数的最大公约数,求最大公约数也可以用下面的函数
def check(mid):
nA = mid // A
nB = mid // B
nC = mid // C
return (nA + nB - nC) < N # 小于mid的数中有多少个能被A整除或能被B整除的数:nA+nB-nC,减去nC的原因是可能会有一些数被重复计算,比如A=2,B=3,mid=12,那么中间的6和12都会被重复计算,因此要减去mid整除A和B的最小公倍数。
while lo < hi:
mid = lo + (hi - lo) // 2
if check(mid):
lo = mid + 1
else:
hi = mid
return lo % mod
# N, A, B = 4, 2, 3
N, A, B = 5, 2, 4
print(Solution().nthMagicalNumber(N, A, B))