leetcode 264. Ugly Number II(丑数 2)

Write a program to find the n-th ugly number.

Ugly numbers are positive numbers whose prime factors only include 2, 3, 5.

Example:

Input: n = 10
Output: 12
Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.

263题只让判断是否是丑数,而这道题是让求出第n个丑数
丑数的定义是只能被2,3,5的素因数整除
第一个丑数是1

思路:
可以保存每个丑数* 2, * 3, * 5到一个优先队列,然后取第n-1个
比如保存 1* 2, 1* 3, 1* 5,到优先队列,然后取最小的2出来,再保存2 * 2, 2 * 3, 2 * 5
因为涉及到排序,所以time complexity是O(NlogN)

这里用O(N)的方法,
用变量分别保存因子2, 3, 5的index,这个index指的是指向第几个丑数,而不是顺序的1,2,3…
因为如果是指向顺序的1,2…,就有7的倍数存在,违背了丑数的定义。
每次用第 i 个丑数分别乘2,3,5,取其中最小的作为下一个丑数,如果下一个是2的倍数,就把2的index加1,即下一次用下一个丑数来乘2,同理3和5,注意这里一定要同时更新2,3,5的index,而不是if…else,因为有相同的数存在,比如2和3的公倍数6,要跳过6就要同时更新2和3的index。
用list保存一系列丑数,最后返回第n个丑数即可。
第一个丑数是1,所以要先在结果list中存入1。

比如:
丑数     ×2           ×3         ×5
1:           2,         3,        5
2:          4,         6,       10
3:          6,         9,       15

然后是运行时间,试了一下cpp,如果声明vector是static,那么每次调用函数时就不会再重新产生丑数,运行时间是0ms,如果不声明static,testing每次调用时都会从头再产生丑数,运行时间是4ms

    int nthUglyNumber(int n) {
        static vector<int> nums{1};
        static int i2 = 0;
        static int i3 = 0;
        static int i5 = 0;
        
        while (nums.size() < n) {
            const int next2 = nums[i2] * 2;
            const int next3 = nums[i3] * 3;
            const int next5 = nums[i5] * 5;
            int next = min(next2, min(next3, next5));
            
            //不能用if..else,因为有公倍数的存在,比如6,要同时更新几个数的index
            //也不能用switch..case,因为next2, next3, next5是变量,而case中要求常数
            if (next == next2) {
                i2 ++;
            }
            
            if (next == next3) {
                i3 ++;
            }
            
            if (next == next5) {
                i5 ++;
            }
            
            nums.push_back(next);
        }
        
        return nums[n - 1];
    }

java版
java的非static函数中不能用static变量

    public int nthUglyNumber(int n) {
        if(n <= 0) {
            return -1;
        }
        
        List<Integer> uglyNums = new ArrayList<Integer>(){{add(1);}};
        int ind2 = 0;
        int ind3 = 0;
        int ind5 = 0;
        
        for(int i = 2; i <= n; i++) {
            int next2 = 2 * uglyNums.get(ind2);
            int next3 = 3 * uglyNums.get(ind3);
            int next5 = 5 * uglyNums.get(ind5);
            
            int next = Math.min(Math.min(next2, next3), next5);
            
            //不能用if..else,因为有公倍数的存在,比如6,要同时更新几个数的index
            //也不能用switch..case,因为next2, next3, next5是变量,而case中要求常数
            if (next == next2) {
                ind2 ++;
            } 
            if (next == next3) {
                ind3 ++;
            } 
            if (next == next5) {
                ind5 ++;
            }
            uglyNums.add(next);
        }
        return uglyNums.get(n - 1);   
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值