33.丑数

题目描述

         把只包含因子2、3和5的数称作丑数(Ugly Number);

         例如6、8都是丑数,但14不是,因为它包含因子7;

         习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数;

解题思路

         先说一种暴力解决的方法,以提供思路;

         如果p是丑数,那么p=2^x * 3^y * 5^z,那么只要赋予x,y,z不同的值就能得到不同的丑数;

         如果要顺序找出丑数,要知道下面几个特点: 对于任何丑数p:2*p,3*p,5*p都是丑数,并且2*p<3*p<5*p;如果p<q, 那么2*p<2*q,3*p<3*q,5*p<5*q;

          由于1是最小的丑数,那么从1开始,把2*1,3*1,5*1,进行比较,最小的那个就是1的下一个丑数,也就是2*1;

          这个时候,多了一个丑数‘2’,也就又多了3个可以比较的丑数,2*2,3*2,5*2,

          这个时候就把之前‘1’生成的丑数和‘2’生成的丑数加进来也就是(3*1,5*1,2*2,3*2,5*2)进行比较,找出最小的;

          如此循环下去就会发现,每次选进来一个丑数,该丑数又会生成3个新的丑数进行比较;

          接下来,说一种O(n)的算法;

          既然有p<q, 那么2*p<2*q,那么“我”在前面比你小的数都没被选上,你后面生成新的丑数一定比“我”大吧,那么你乘2

生成的丑数一定比我乘2的大吧,那么在我选上之后你才有机会选上。

         其实每次我们只用比较3个数:用于乘2的最小的数、用于乘3的最小的数,用于乘5的最小的数。也就是比较(2*x , 3*y, 5*z) ,x>=y>=z的,

         重点说说下面代码中p的作用:int p[] = new int[] { 0, 0, 0 }; p[0]表示最小用于乘2比较数在数组a中的【位置】。

    final int d[] = {2, 3, 5};

    private int finMin(int num2, int num3, int num5) {
        int min = Math.min(num2, Math.min(num3, num5));
        return min == num2 ? 0 : min == num3 ? 1 : 2;
    }

    public int GetUglyNumber_Solution(int index) {

        if (index == 0){
            return 0;
        }

        int a[] = new int[index];

        a[0] = 1;    //1是第一个丑数

        int p[] = new int[]{0, 0, 0};
        int num[] = new int[]{2, 3, 5};
        int cur = 1;

        while (cur < index) {

            int m = finMin(num[0], num[1], num[2]);

            if (a[cur - 1] < num[m])
                a[cur++] = num[m];

            p[m] += 1;

            num[m] = a[p[m]] * d[m];
        }

        return a[index - 1];
    }

猜你喜欢

转载自blog.csdn.net/regemc/article/details/80139647