1201. 丑数 III
class Solution:"""巧用二分搜索1201. 丑数 IIIhttps://leetcode.cn/problems/ugly-number-iii/"""def nthUglyNumber(self, n: int, a: int, b: int, c: int) -> int:# 题目说本题结果在 [1, 2 * 10^9] 范围内left, right = 1, 2e9# 搜索左侧边界的二分搜索 左闭右闭 [left, right]while left <= right:mid = left + (right-left)//2if self.f(mid, a, b, c) >= n:right = mid - 1else:left = mid + 1return int(left)def f(self, num, a, b, c):"""函数 f 是一个单调函数, 随着num的增加而增加计算 [1..num] 之间有多少个能够被 a 或 b 或 c 整除的数字:param num::param a::param b::param c::return:"""set_a = num // aset_b = num // bset_c = num // cset_ab = num // lcm(a, b)set_ac = num // lcm(a, c)set_bc = num // lcm(c, b)set_abc = num // lcm(lcm(a, b), c)# 集合论定理:A + B + C - A ∩ B - A ∩ C - B ∩ C + A ∩ B ∩ Creturn set_a + set_b + set_c - set_ac - set_ab - set_bc + set_abc# 求两个数的最大公约数(greatest common divisor),辗转相除法
def gcd(a, b):# 保证a>bif a < b:return gcd(b, a)if b == 0:return areturn gcd(b, a % b)# 求两个数的最小公倍数(least common multiple)
def lcm(a, b):return a * b/gcd(a, b)