long min(long a, long b) {
return a<b?a:b; }long LCM(long a,long b){ long Multi = a * b; //求最小公倍数 while(b > 0){ long tmp = a % b; a = b; b = tmp; } return Multi/a; } int nthUglyNumber(int n, int a, int b, int c) { long ab = LCM(a, b); long ac = LCM(a, c); long bc = LCM(b, c); long abc = LCM(ab, c); long l = min(a, min(b, c)); long r = n*l; while (l < r) {//这个才是点睛之笔 大佬厉害 long m = l + (r - l) / 2; long count = m / a + m / b + m / c - m / ab - m / ac - m / bc + m / abc;//容斥定理,一个丑数肯定是由若干个基本丑数相乘而来,有的丑数只有n1个a得到 if (count < n) { l = m + 1; } else { r = m; } } return l; }
参考大佬的代码和讲解而成。这代码越想越着迷!
第一
采用容斥定理,判断一个数前面有多少个丑数
x = an1bn2c*n3+m; n1+n2+n3 = m;已知 a,b,c和x求m0
1.该数只能被a整除 (该数一定是a 的整数倍)
2.该数只能被b整除 (该数一定是b 的整数倍)
3.该数只能被c整除 (该数一定是c 的整数倍)
4.该数只能被a和b同时整除 (该数一定是a、b最小公倍数的整数倍)
5.该数只能被a和c同时整除 (该数一定是a、c最小公倍数的整数倍)
6.该数只能被b和c同时整除 (该数一定是b、c最小公倍数的整数倍)
7.该数只能被a和b和c同时整除(该数一定是a、b、c的最小公倍数的整数倍)
所以,我们只需要分别计算以上七项就能得到结果了!让我们分别来看(用MCM+下标表示最小公倍数):
情况1 = X/a - 情况4 - 情况5 - 情况7 情况2 = X/b - 情况4 - 情况6 - 情况7 情况3 = X/c -
情况5 - 情况6 - 情况7 情况4 = X/MCM_a_b - 情况7 情况5 = X/MCM_a_c - 情况7 情况6 =
X/MCM_b_c - 情况7 情况7 = X/MCM_a_b_c作者:Alfeim
链接:https://leetcode-cn.com/problems/ugly-number-iii/solution/er-fen-fa-si-lu-pou-xi-by-alfeim/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处
第二
寄托于二分算法
第三
循环终止的条件,可以直接找到第n个丑数,而不是包含n个丑数的数