LC 1201. Ugly Number III
https://leetcode.com/problems/ugly-number-iii/
最开始看到这题我有点懵,分析了很久才理清思路:
- 首先这个数肯定是 a*n or b*n or c*n, 关键就是我们确定这个n
- 然后对于a * n, 中间可能还有许多可以整除b, c的元素,所以实际上 a * n肯定是 m-th ugly number, 并且m >= n.
- 我们可以先猜测是 a*n, 然后计算a*n是 mth-ugly number, 然后使用二分法逼近
如果只有a, b两个元素,比较好搞:
- 对于 a*n , 期间有 a*n / b个元素是被b整除的
- 然后需要减去 a*n / lcm(a, b)
- m = n + an / b - an / lcm(a, b)
但是如果是a, b, c三个元素,如何各项的正负号,尤其是lcm(a, b, c)的正负号. 各项应该是这样的:
- n, an/b, an/c. 这个是正号
- an/lcm(a,b), an/lcm(b,c), an/(a,c). 这些都是负号
- an/lcm(a, b, c). 这个是正号还是负号?有没有额外系数?
我觉得可以针对一个值分析,就是lcm(a, b, c), 计算它被计入的次数:
- 在第一项,他们被计入了+3次。
- 在第二项,他们被计入了-3次。
- 而他们应该只被计入1次,所以第三项系数应该是1,符号是正号。
def lcm(x, y):
return x * y // gcd(x, y)
def gcd(x, y):
while y != 0:
x, y = y, x % y
return x
def test(abc):
a, b, c = abc
Gab = lcm(a, b)
Gac = lcm(a, c)
Gbc = lcm(b, c)
Gabc = lcm(Gab, c)
s, e = 1, n
found = False
while s <= e:
m = (s + e) // 2
x = m + (a * m) // b + (a * m) // c
y = (a * m) // Gab + (a * m) // Gac + (a * m) // Gbc
z = (a * m) // Gabc
seq = x - y + z
if seq == n:
found = True
break
elif seq > n:
e = m - 1
else:
s = m + 1
return found, a * m