【剑指offer】【动态规划】49.丑数

题目链接:https://leetcode-cn.com/problems/chou-shu-lcof/

常规解法

从0开始依次判断是不是丑数,判断到第n个返回; 算法直观,代码简介,但是效率不高,而且直接超时了

class Solution {
public:
    bool isUgly(int n)
    {
        while(n % 2 == 0)
            n /= 2;
        while(n % 3 == 0)
            n /= 3;
        while(n % 5 == 0)
            n /= 5;
        return n == 1 ? true : false;
    }


    int nthUglyNumber(int n) {
        int unlyNum = 0;
        int number = 0;
        while(unlyNum < n)
        {
            ++number;
            if(isUgly(number))
                ++unlyNum;
        }
        return number;
    }
};

三路归并

  1. 利用丑数的定义,并且一个丑数乘以2,3,5以后仍然是一个丑数。
  2. 假设当前存在 3 个数组 nums2, nums3, nums5 分别代表丑数序列从 1 开始分别乘以 2, 3, 5 的序列, 即
    nums2 = {1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2,...}
    nums3 = {1 * 3, 2 * 3, 3 * 3, 4 * 3, 5 * 3, 6 * 3,...}
    nums5 = {1 * 5, 2 * 5, 3 * 5, 4 * 5, 5 * 5, 6 * 5,...}
    那么, 最终的丑数序列实际上就是这 3 个有序序列对的合并结果, 计算丑数序列也就是相当于 合并 3 个有序序列。
  3. 合并 3 个有序序列, 每一个序列都各自维护一个指针, 然后比较指针指向的元素的值, 将最小的放入最终的合并数组中, 并将相应指针向后移动一个元素。
class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> q(1, 1); // 1放入丑数集合
        int i = 0, j = 0, k = 0; //i j k分别表示2,3,5三个质因子
        while(--n)
        {
            //依次往q中插入数,将i*2,j*3,k*5中最小的放入数组;
            //三路归并
            int x = min(q[i] * 2, min(q[j] *3, q[k] * 5));
            q.push_back(x);

            //如果有重复  都要往后移动
            if(q[i] * 2 == x) i++;
            if(q[j] * 3 == x) j++;
            if(q[k] * 5 == x) k++;
        }
        return q.back();
    }
};

参考:https://leetcode-cn.com/problems/chou-shu-lcof/solution/chou-shu-ii-qing-xi-de-tui-dao-si-lu-by-mrsate/

posted @ 2020-04-28 23:19  NaughtyCoder  阅读(111)  评论(0)    收藏  举报