【LeetCode】【数学】剑指 Offer 49. 丑数 思路解析和代码

剑指 Offer 49. 丑数

题目链接

个人思路

题意

准确理解:丑数是只能被2,3,5整除的数字,因此对一个数字是否是丑数,应让这个数字连续被2整除,连续被3整除,连续被5整除,若最后整除后剩下的数字是1,则说明是丑数,否则不是丑数

思路

错误思路
  • 最初理解成为数字能被2或3或5整除,发现理解有误
  • 而后又理解为不能被大于5的素数整除,所以使用素数打表,但无法存放大规模的素数
优化思路——空间换时间

所有的丑数都是之前的丑数的基础上乘2,乘3,乘5得到,因此将丑数保存在数组中,通过对已有丑数运算来得到其他的丑数,避免了对非丑数的计算

  • 用maxUglyNum存放当前最大的丑数

生成丑数的过程:

  • 对之前存储的丑数做乘2,乘3,乘5运算,找到刚刚大于maxUglyNum,得到bigger2,bigger3,bigger5,其中最小的为下一个丑数
  • 用index2,index3,index5存放划分点的下标,即下标在index2之前的,乘2后都比maxUglyNum小,在idnex2之后的,乘2后比maxUglyNum大
  • 每次生成一个丑数,直到找到第n个丑数

注意

  • 1是丑数

个人错误思路代码

class Solution {
public:
    static const int MAXN = 100005;
    bool isPrime[MAXN];
    //vector<bool> isPrime;
    int prime[MAXN], pNum = 0;
    void findPrime(){
        memset(isPrime, true, sizeof(isPrime));
        isPrime[0] = isPrime[1] = false;
        for(int i = 2; i < MAXN; ++i){
            if(isPrime[i]){
                prime[pNum++] = i;
                for(int j = i + i; j < MAXN; j += i){
                    isPrime[j] = false;
                }
            }
        }
    }

    bool judge(int n){
        if(n == 1){
            return true;
        }
        for(int i = 0; i < pNum; ++i){
            if(n % prime[i] == 0){
                if(prime[i] > 5){
                    return false;
                }
                int another = n / prime[i];
                if(isPrime[another] == true){
                    return false;
                }
            }
        }
        return true;
    }
    int nthUglyNumber(int n) {
        findPrime();

        int index = 1;
        int cnt = 0;
        while(1){
            if(cnt == n){
                index--;
                break;
            }
            if(judge(index)){
                cnt++;
            }
            index++;
        }
        return index;
    }
};
未优化的代码——超时
class Solution {
public:
    bool judge(int num){
        while(num % 2 == 0){
            num /= 2;
        }
        while(num % 3 == 0){
            num /= 3;
        }
        while(num % 5 == 0){
            num /= 5;
        }
        if(num == 1){
            return true;
        }else{
            return false;
        }
    }
    int nthUglyNumber(int n) {
        int index = 1;
        int cnt = 0;
        while(1){
            if(cnt == n){
                break;
            }
            if(judge(index)){
                cnt++;
            }
            if(cnt < n){
                index++;
            }
        }
        return index;
    }
};
以空间换时间的优化代码
class Solution {
public:
    int ugly[2000];
    int nthUglyNumber(int n) {
        ugly[0] = 0;
        ugly[1] = 1;
        int cur = 1;//当前是第几个丑数下标
        int maxUglyNum = ugly[cur];//当前最大的丑数
        int index2 = 0, index3 = 0, index5 = 0;//2,3,5的划分点,比index2小的,乘上2也都小于maxUglyNum
        int bigger2, bigger3, bigger5;//乘2,3,5后得到的数字

        if(n <= 0){
            return 0;
        }

        while(1){
            if(cur < n){
                cur++;
            }
            else{
                break;
            }
            while(ugly[index2] * 2 <= maxUglyNum){
                index2++;
            }
            bigger2 = ugly[index2] * 2;

            while(ugly[index3] * 3 <= maxUglyNum){
                index3++;
            }
            bigger3 = ugly[index3] * 3;

            while(ugly[index5] * 5 <= maxUglyNum){
                index5++;
            }
            bigger5 = ugly[index5] * 5;
            ugly[cur] = min(bigger2, min(bigger3, bigger5));

            maxUglyNum = ugly[cur];
        }

        return ugly[cur];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值