LeetCode的第1201道题目,题目如下:
Write a program to find the n-th ugly number.
Ugly numbers are positive integers which are divisible by a or b or c.
注意这道题目与Ugly Number II的区别,Ugly Number II中的“丑数”的因数完全由给定的组成,可以用动态规划来解,可以参考这篇博文Ugly Number II.
而Ugly Number III中的“丑数”是指只要某个数可以被给定的数整除即可,可以包含其他因数。求解思路分两步,第一步,完成给定任意一个整数n,计算出1-n中有多少个数是丑数,时间复杂度是O(1)级别;第二步,利用二分查找进行搜索,不难得出正确答案。代码如下:
public static int nthUglyNumber(int n, int a, int b, int c) {
int res = 0;
int high = n * a;
int low = a;
while(low <= high){
int mid = low + (high - low) / 2;
if(countNthUglyNumber(mid,a,b,c) > n)
high = mid - 1 ;
else if(countNthUglyNumber(mid,a,b,c) < n){
low = mid + 1;
}
else{
if(countNthUglyNumber(mid - 1,a,b,c) < n)
return mid;
else
high = mid - 1;
}
}
return res;
}
/**
* 给定n和a,b,c,找到n以内中因数包含a,b,c的个数
* @param n
* @param a
* @param b
* @param c
* @return
*/
public static long countNthUglyNumber(int n, int a, int b, int c) {
long res = 0;
long ab = get_lcm(a,b);
long ac = get_lcm(a,c);
long bc = get_lcm(b,c);
long abc = get_lcm(ab,c);
System.out.println(abc);
res = n / a + n / b - n / ab + n / c - n/ac - n/bc + n / abc;
//System.out.println(n + " " + res + " " + ab + " " + abc);
return res;
}
// 最大公约数
public static long get_gcd(long n1, long n2) {
long gcd = 0;
if (n1 < n2) {// 交换n1、n2的值
n1 = n1 + n2;
n2 = n1 - n2;
n1 = n1 - n2;
}
if (n1 % n2 == 0) {
gcd = n2;
}
while (n1 % n2 > 0) {
n1 = n1 % n2;
if (n1 < n2) {
n1 = n1 + n2;
n2 = n1 - n2;
n1 = n1 - n2;
}
if (n1 % n2 == 0) {
gcd = n2;
}
}
return gcd;
}
// 最小公倍数
public static long get_lcm(long n1, long n2) {
return n1 * n2 / get_gcd(n1, n2);
}