找出第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个丑数

猜你喜欢

转载自blog.csdn.net/lucifly/article/details/51115161