Leetcode 878: Nth Magical Number

题目:



  这道题的题意是寻找一个数,这个数是第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))

你可能感兴趣的:(Leetcode 878: Nth Magical Number)