找出第n個ugly number

找出第n個ugly number

LeetCode第264題,Ugly Number II

原題連接

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.

參考了一些網上的博客之後綜合的一些想法,總結了一下。

思路

   首先,uglynumber是隻由235乘出來的數,所以一個數a是ugly數,
   那麼a乘(或者除)2(或3或5)也應該是uglynumber。
   換言之現有小於M的所有uglynumber組成的數組ugly[],
   那麼接下來大於M的新uglynumber一定可以由數組ugly[]乘2(或3或5)生成。
   其次,要找第n個uglynumber的最好可以按順序依次生成新的uglynumber直到第n個。
  綜上有下面的算法(僞代碼):
var ugly[m];//存現有的小於M=ugly[m-1])的所有uglynumber
//初始化ugly[0] = 1;
while(--n)
{
    var M = ugly[m-1];
    for(i=0;i<m;i++)
    {
        if(ugly[i]*2 > M) 
        {
            ugly[m] = ugly[i]*2;
            break;
        }
        else if(ugly[i]*3 > M) 
        {
            ugly[m] = ugly[i]*3;
            break;
        }
        else if(ugly[i]*5 > M) 
        {
            ugly[m] = ugly[i]*5;
            break;
        }
    }
}

遍歷已有的有序uglynumber數組ugly[]中的元素,分別乘以2,3,5;
得到的三個乘積中比數組中最大的數M 大的最小的一個數,即是最小的新的uglynumber,因爲數組中存的是所有M 小的uglynumber,所以如果比M 小的數肯定是已經存在數組中了;
將新數存入數組中,重複n遍即可找到第n個;

——————我是分割線————————————-

上面的算法s是O(n*n)的複雜度,但每一次都要遍歷ugly[]數組其實是不必要的。
原因如下:

如果找出第一個乘以2大於M元素是ugly[L2], 並且ugly[L2]是新的uglynumber,那麼下一次乘以2的元素從L2+1開始就可以了,因爲數組是有序的,ugly[L2+1]*2 > ugly[L2]*2 = M;
對於3和5同理

所以有下面的改進(僞代碼)O(n)

var L2 = L3 = L5 = 0;
var ugly[m];//存現有的小於M=ugly[m-1])的所有uglynumber
//初始化ugly[0] = 1;
while(--n)
{
    var min = min(ugly[L2]*2,ugly[L3]*3,ugly[L5]*5);
    if(ugly[L2]*2 == min) L2++;
    if(ugly[L3]*3 == min) L3++;
    if(ugly[L5]*5 == min) L5++;
    ugly[m] = min;
}

Q.E.D.

參考:LeetCode:Ugly Number II - 醜數2:找出第n個醜數

發佈了23 篇原創文章 · 獲贊 2 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章