力扣之丑数III

题目

请你帮忙设计一个程序,用来找出第 n 个丑数。
丑数是可以被 a 或 b 或 c 整除的 正整数。

示例 1:
输入:n = 3, a = 2, b = 3, c = 5
输出:4
解释:丑数序列为 2, 3, 4, 5, 6, 8, 9, 10… 其中第 3 个是 4。

示例 2:
输入:n = 4, a = 2, b = 3, c = 4
输出:6
解释:丑数序列为 2, 3, 4, 6, 8, 9, 12… 其中第 4 个是 6。

示例 3:
输入:n = 5, a = 2, b = 11, c = 13
输出:10
解释:丑数序列为 2, 4, 6, 8, 10, 11, 12, 13… 其中第 5 个是 10。

示例 4:
输入:n = 1000000000, a = 2, b = 217983653, c = 336916467
输出:1999999984

提示:
1 <= n, a, b, c <= 10^9
1 <= a * b * c <= 10^18
本题结果在 [1, 2 * 10^9] 的范围内

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ugly-number-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题

验证方法

输入:
1000000000
2
217983653
336916467

正确答案:
1999999984

第一版

直接通过遍历的方式获取,该方法比较笨,但是可以通过该方法验证结果是否准确。后续完整代码会提供用于验证其他方法的结果。
int nthUglyNumber(int n, int a, int b, int c){
    int index = 0;
    for(int i = a; i < 2000000000; i ++){
        if(!(i%a) || !(i%b) || !(i%c)){
            if(++index == n){
                return i;
            }            
            continue;
        }
    }
    return 0;
}

结果:

超出时间限制

第二版

通过二分法定位最终结果。
//求最小公倍数
long fun(int a, int b){
    long m = a, n = b, c;
    while(b!= 0){
        c=a%b;
        a=b;
        b=c;
    }
    return (m*n/a);
}

int nthUglyNumber(int n, int a, int b, int c){
    long temp = 0; 
    long count = 0; 
 
    long max = n*a; 
    long lower = a, hight = max > 2000000000 ? 2000000000 : max; 

    if((b%a) || (c%a)) {
        //b c不能舍弃,需要计算a b c
        long m_ab = fun(a,b);
        long m_ac = fun(a,c);
        long m_bc = fun(b,c);
        long m_abc = fun((int)m_ab, c);
            
        while(lower <= hight) {
            temp = (lower+hight) >> 1;
            count = (temp/a + temp/b + temp/c - temp/m_ab - temp/m_ac - temp/m_bc + temp/m_abc);    

            if(count == n && (!(temp%a) || !(temp%b) || !(temp%c))) {
                return temp;
            }else{
                if(count < n){
                    lower = temp + 1;
                } else {
                    hight = temp - 1;
                }
            }                                       
        }
        return (int)hight;     
    } else {
        //c被抛弃,只需要计算 a
        return a*n;
    }
}

结果:

1999999984

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int nthUglyNumber2(int n, int a, int b, int c){
	int count = 0;
	for(int i = a; i < 2000000000; i ++){
		if(!(i%a) || !(i%b) || !(i%c)){
			//printf("%d\t",i);
			if(++ count == n) {
				return i;
			}
		}
		//if(!(i%30)){
		//	printf("\n");
		//}
	}
	return count;
}

long fun(int a, int b) {
	long t;
	int m, n, c;
	m=a;   n=b;
	while(b!=0)  /* 余数不为0,继续相除,直到余数为0 */ 
	{ 
		c=a%b; 
		a=b;  
		b=c;
	}
	t = (long)m*n/a;	

	//printf("The largest common divisor:%d\n", a);
	//printf("The least common multiple:%ld\n", t);

	return t;
}

int nthUglyNumber(int n, int a, int b, int c){
	long temp = 0;
	int count = 0;

	clock_t start, finish;

	start = clock();
	long m_ab = fun(a,b);
	long m_bc = fun(b,c);
	long m_ac = fun(a,c);
	long m_abc = fun(m_ab,c);
	finish = clock();
	printf(" m fun cost time : %lu\n", finish-start);


	long max = n*a;
	int lower = a, hight = max > 2000000000 ? 2000000000 : (int)max;

	while(lower < hight) {

		temp = ((long)lower+hight) >> 1;
		count = (temp/a + temp/b + temp/c - temp/m_ab - temp/m_ac - temp/m_bc + temp/m_abc);	

		//printf("%d--%d\n", lower, hight);
		//printf("temp: %ld -- count:%d\n", temp , count);

		if(count == n && (!(temp%a) || !(temp%b) || !(temp%c))) {
			return temp;
		}else{
			if(count < n){
				lower = temp + 1;
			} else {
				hight = temp - 1;
			}
		}					
	}

	return lower;
}

int main(int argc, char* argv[]){

	if(argc < 5){
		printf("pls input 4 args!\n");
		return 0;
	}

	int n = atoi(argv[1]);
	int a = atoi(argv[2]);
	int b = atoi(argv[3]);
	int c = atoi(argv[4]);

	int ret, ret2;
	clock_t start, finish;

	printf("------- normal fun start! --------\n");
	start = clock();
	ret2 = nthUglyNumber2(n,a,b,c);
	finish = clock();
	printf("------- normal fun over! --------\n");
	printf(" normal fun cost time : %lu\n", finish-start);

	printf("------- samrt fun start! --------\n");
	start = clock();
	ret = nthUglyNumber(n,a,b,c);
	finish = clock();
	printf("------- smart fun over! --------\n");
	printf(" smart fun cost time : %lu\n", finish-start);

	printf("ret: %d == %d?\n",ret, ret2);

	return 0;
}

结果:

./a.out 1000000000 2 217983653 336916467
------- normal fun start! --------
------- normal fun over! --------
 normal fun cost time : 12890148
------- samrt fun start! --------
------- smart fun over! --------
 smart fun cost time : 3
ret: 1999999984 == 1999999984?

总结

最终还是二分法比较快速定位到正确值,完整代码可以调试代码与验证结果。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值