[LeetCode]70. Ugly Number II第N個丑數


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

Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.

Note that 1 is typically treated as an ugly number.

Hint:

  1. The naive approach is to call isUgly for every number until you reach the nth one. Most numbers are not ugly. Try to focus your effort on generating only the ugly ones.
  2. An ugly number must be multiplied by either 2, 3, or 5 from a smaller ugly number.
  3. The key is how to maintain the order of the ugly numbers. Try a similar approach of merging from three sorted lists: L1, L2, and L3.
  4. Assume you have Uk, the kth ugly number. Then Uk+1 must be Min(L1 * 2, L2 * 3, L3 * 5).

Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.

 

Subscribe to see which companies asked this question

 

解法1:從2到n循環,對每個數進行isUgly判斷,會超時Time Limit Exceeded

class Solution {
public:
    int nthUglyNumber(int n) {
        int num = 2;
        while(n > 1) {
            if(isUgly(num)) --n;
            ++num;
        }
        return --num;
    }
private:
    bool isUgly(int num) {
        while(num > 0 && num % 2 == 0) num /= 2;
        while(num > 0 && num % 3 == 0) num /= 3;
        while(num > 0 && num % 5 == 0) num /= 5;
        return num == 1;
    }
};

 

解法2:根據提供的Hint,我們知道丑陋數序列可以拆分為下面3個子列表:

(2) 1×2, 2×2, 3×2, 4×2, 5×2, …
(3) 1×3, 2×3, 3×3, 4×3, 5×3, …
(5) 1×5, 2×5, 3×5, 4×5, 5×5, …

一個新的丑數可以看做是一個舊的丑數乘以2,3,5得到的(第一個丑數是1,第二個為2,則第二個可以看做第一個丑數*2得到了第二個丑數(1*2、1*3和1*5中的最小者)),本題解題難點在於維護丑數數列為從小到大排列的順序。

根據上述思路可以做如下實現:

  • 維護三個列表l2,l3,l5,分別是當前處理的丑數num的2,3,5倍,因此三個列表組內均是遵從從小到大排列的規則;
  • 每次獲得三個列表的第一個結點(最小的結點)最為當前丑數num,根據當前丑數值想三個列表末端插入新的較大的丑數值,等待后續處理;
  • 若列表的第一個結點與當前丑數num相等,則刪除列表第一個結點(表示該丑數已經被計數);
  • 題目的初始條件為num = 1, count = 1;
class Solution {
public:
    int nthUglyNumber(int n) {
        int count = 1;
        int num = 1;
        list<int> l2;
        list<int> l3;
        list<int> l5;

        while(count != n)
        {
            l2.push_back(2*num);
            l3.push_back(3*num);
            l5.push_back(5*num);

            int l2min = l2.front();
            int l3min = l3.front();
            int l5min = l5.front();

            int minNum = min(l2min, min(l3min, l5min));
            if(l2min == minNum) l2.pop_front();
            if(l3min == minNum) l3.pop_front();
            if(l5min == minNum) l5.pop_front();
            num = minNum;
            ++count;
        }
        return num;
    }
};

改進:對於乘以2而言,肯定存在某一個丑數t2,使得排在它之前的每一個丑數乘以2得到的結果都會小於已有最大丑數,在它之后的每個丑數乘以2得到的結果都會大於當前最大丑數。我們只需要記下這個丑數的位置,同時每次生成新的丑數時去更新這個t2。對於3和5,同樣存在t3和t5。

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> uglyNumSeq(1, 1);
        int i2 = 0, i3 = 0, i5 = 0;
        while (uglyNumSeq.size() < n) {
            int n2 = uglyNumSeq[i2] * 2;
            int n3 = uglyNumSeq[i3] * 3;
            int n5 = uglyNumSeq[i5] * 5;
            int next = min(n2, min(n3, n5));
            if (next == n2) ++i2;
            if (next == n3) ++i3; //注意不用else if,因為不同序列可能有相同值
            if (next == n5) ++i5;
            uglyNumSeq.push_back(next);
        }
        return uglyNumSeq.back();
    }
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM