Code

Heap

可發現此法得到的數字會遠大於用 DP 去解的,要用 long 才不會 overflow。

class Solution {
public:
    int nthUglyNumber(int n) {
        priority_queue <long, vector<long>, greater<long> > min_heap;
        unordered_set<long> ugly;
        min_heap.push(1);
        for(int i = 0; i < n; i++) {
            long m = min_heap.top();
            if(ugly.count(m * 2) == 0) {
                min_heap.push(m * 2);
                ugly.insert(m * 2);
            }
            if(ugly.count(m * 3) == 0) {
                min_heap.push(m * 3);
                ugly.insert(m * 3);
            }
            if(ugly.count(m * 5) == 0) {
                min_heap.push(m * 5);
                ugly.insert(m * 5);
            }
            if (i != n - 1) min_heap.pop();
        }   
        return min_heap.top();
    }
};

不用 set 而消除 duplicate 的寫法:

class Solution {
public:
    int nthUglyNumber(int n) {
        priority_queue <long, vector<long>, greater<long> > min_heap;
        min_heap.push(1);
        long m = 1;
        for(int i = 0; i < n; i++) {
            m = min_heap.top();
            min_heap.pop();
            while(!min_heap.empty() && m == min_heap.top()) {
                min_heap.pop();
            }
            min_heap.push(m * 2);
            min_heap.push(m * 3);
            min_heap.push(m * 5);
 
        }   
        return m;
    }
};

DP-like

TLE 版本,直接使用 Ugly Number 中的解法去暴力搜索。

要想辦法加速。可觀察到:若一個數字是 ugly number,則它二的、三的、五的倍數都會是 ugly number。

class Solution {
public:
    int nthUglyNumber(int n) {
        int iter = 1;
        int count = 0;
        while(count < n) {
            if (isUgly(iter)) count++;
            iter++;
        }
        return iter - 1;
    }
 
    bool isUgly(int n) {
        if(n == 0) return false;
        if(n == 1) return true;
        while(n % 2 == 0) n /= 2;
        while(n % 3 == 0) n /= 3;
        while(n % 5 == 0) n /= 5;
        return n == 1? true : false;
    }
 
};

錯誤加速版本:

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> ugly(n);
        ugly[0] = 1;
        int p1 = 0;
        int p2 = 0;
        int p3 = 0;
        for(int i = 1; i < n; i++) {
            ugly[i] = min({2 * p1, 3 * p2, 5 * p3});
            if (ugly[i] == 2 * p1) p1++;
            if (ugly[i] == 3 * p2) p2++;
            if (ugly[i] == 5 * p3) p3++;
        }   
        return ugly[n-1];
    }
};

正確加速版本:

要將 p1, p2, p3 包在 ugly 中使用(ex: ugly[p1])是因為 ugly number 只能是 ugly number 的 2、3、5 倍,如果單純用 p1, p2, p3,就會乘到像是 7 這類不是 ugly number 的數字,造成結果不正確。

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> ugly(n);
        ugly[0] = 1;
        int p1 = 0;
        int p2 = 0;
        int p3 = 0;
        for(int i = 1; i < n; i++) {
            ugly[i] = min({2 * ugly[p1], 3 * ugly[p2], 5 * ugly[p3]});
            if (ugly[i] == 2 * ugly[p1]) p1++;
            if (ugly[i] == 3 * ugly[p2]) p2++;
            if (ugly[i] == 5 * ugly[p3]) p3++;
        }   
        return ugly[n-1];
    }
};