牛客网-剑指offer-丑数

题目

把只包含因子2、3和5的数称作丑数(Ugly Number)。
例如6、8都是丑数,但14不是,因为它包含因子7。
习惯上我们把1当做是第一个丑数。
求按从小到大的顺序的第N个丑数。

思路:
1. 暴力法:
先判断一个数是不是 丑数,然后从0开始判断,知道符合 丑数的数目 累加到 N 。

2. 三个取最小值法:
     一个丑数必然是 2 ,3,5  这个三个因为的 一个 或多个相乘。
     初始的几个数为 [ 1,2,3,5 ]    对吗?  不对。
          初始的几个数据为  **[ 1,2,3, 4, 5 ]**
     4 为二乘了两次。然后呢,是 3*2 =6  。这个 6 又是怎么比较出来的呢。
              我用 3*2     ==》 所有2 的倍数,并且因子也是丑数的,因为, 1*2 ,2*2 ,已经用过了,现在只能用 3*2 了。
                      2*3   ==》 同理,所有 3的倍数,并且因子也是丑数的, 1*3  已经用过了。
                      2*5   ==》      所有 5的倍数,并且因子也是丑数的, 1*5  已经用过了。
            所以上述的方法每次只需要比较三个数。并且不遗不漏。

代码如下:

public class Solution {
    public int GetUglyNumber_Solution(int index) {
        if(index<=0)return 0;
        ArrayList  list = new ArrayList();
        list.add(1); // 1
        int i2=0;
        int i3=0;
        int i5=0;

        int min=0;
        for(int i=1;iint m2 = list.get(i2)*2;
            int m3 = list.get(i3)*3;
            int m5 = list.get(i5)*5;
            System.out.println("i为 "+i+" , m2 = "+ m2 +" , m3 = "+ m3 +" , m5 = "+ m5 );
            System.out.println("i2 为 " +i2 +",i3 为 " +i3 + ",i5 为 " +i5 );
            System.out.println("i为 "+i+" , list.get(i2) "+ list.get(i2) +" , list.get(i3) = "+ list.get(i3) +" , list.get(i5) = "+ list.get(i5) );

            min = Math.min(m2,Math.min(m3,m5));

            if(min == m2){
                i2++;
            }
            if(min == m3){
                i3++;
            }
            if(min == m5){
                i5++;
            }
            System.out.println("i为 "+i+" , m2 = "+ m2 +" , m3 = "+ m3 +" , m5 = "+ m5 +" , min = "+min);
            System.out.println("i2 为 " +i2 +",i3 为 " +i3 + ",i5 为 " +i5 );



            list.add(min);
            System.out.println(list);
            System.out.println( );
            System.out.println( );

        }

        return list.get(list.size()-1);

    }
}

运算的结果如下:


i为 1 , m2 = 2 , m3 = 3 , m5 = 5
i2 为 0,i3 为 0,i5 为 0
i为 1list.get(i2) 1list.get(i3) = 1list.get(i5) = 1
i为 1 , m2 = 2 , m3 = 3 , m5 = 5 , min = 2
i2 为 1,i3 为 0,i5 为 0
[1, 2]


i为 2 , m2 = 4 , m3 = 3 , m5 = 5
i2 为 1,i3 为 0,i5 为 0
i为 2list.get(i2) 2list.get(i3) = 1list.get(i5) = 1
i为 2 , m2 = 4 , m3 = 3 , m5 = 5 , min = 3
i2 为 1,i3 为 1,i5 为 0
[1, 2, 3]


i为 3 , m2 = 4 , m3 = 6 , m5 = 5
i2 为 1,i3 为 1,i5 为 0
i为 3list.get(i2) 2list.get(i3) = 2list.get(i5) = 1
i为 3 , m2 = 4 , m3 = 6 , m5 = 5 , min = 4
i2 为 2,i3 为 1,i5 为 0
[1, 2, 3, 4]


i为 4 , m2 = 6 , m3 = 6 , m5 = 5
i2 为 2,i3 为 1,i5 为 0
i为 4list.get(i2) 3list.get(i3) = 2list.get(i5) = 1
i为 4 , m2 = 6 , m3 = 6 , m5 = 5 , min = 5
i2 为 2,i3 为 1,i5 为 1
[1, 2, 3, 4, 5]


i为 5 , m2 = 6 , m3 = 6 , m5 = 10
i2 为 2,i3 为 1,i5 为 1
i为 5list.get(i2) 3list.get(i3) = 2list.get(i5) = 2
i为 5 , m2 = 6 , m3 = 6 , m5 = 10 , min = 6
i2 为 3,i3 为 2,i5 为 1
[1, 2, 3, 4, 5, 6]


i为 6 , m2 = 8 , m3 = 9 , m5 = 10
i2 为 3,i3 为 2,i5 为 1
i为 6list.get(i2) 4list.get(i3) = 3list.get(i5) = 2
i为 6 , m2 = 8 , m3 = 9 , m5 = 10 , min = 8
i2 为 4,i3 为 2,i5 为 1
[1, 2, 3, 4, 5, 6, 8]


i为 7 , m2 = 10 , m3 = 9 , m5 = 10
i2 为 4,i3 为 2,i5 为 1
i为 7list.get(i2) 5list.get(i3) = 3list.get(i5) = 2
i为 7 , m2 = 10 , m3 = 9 , m5 = 10 , min = 9
i2 为 4,i3 为 3,i5 为 1
[1, 2, 3, 4, 5, 6, 8, 9]


i为 8 , m2 = 10 , m3 = 12 , m5 = 10
i2 为 4,i3 为 3,i5 为 1
i为 8list.get(i2) 5list.get(i3) = 4list.get(i5) = 2
i为 8 , m2 = 10 , m3 = 12 , m5 = 10 , min = 10
i2 为 5,i3 为 3,i5 为 2
[1, 2, 3, 4, 5, 6, 8, 9, 10]


i为 9 , m2 = 12 , m3 = 12 , m5 = 15
i2 为 5,i3 为 3,i5 为 2
i为 9list.get(i2) 6list.get(i3) = 4list.get(i5) = 3
i为 9 , m2 = 12 , m3 = 12 , m5 = 15 , min = 12
i2 为 6,i3 为 4,i5 为 2
[1, 2, 3, 4, 5, 6, 8, 9, 10, 12]


12

总结:

* 这种思路的关键在于怎样确保数组里面的丑数是排好序的。
 * 我们假设数组中已经有若干个丑数,排好序后存在数组中。
 * 我们把现有的最大丑数记做M。
 * 现在我们来生成下一个丑数,该丑数肯定是前面某一个丑数乘以2、3或者5的结果。
 * 我们首先考虑把已有的每个丑数乘以2。在乘以2的时候,能得到若干个结果小于或等于M的。
 * 由于我们是按照顺序生成的,小于或者等于M肯定已经在数组中了,我们不需再次考虑;
 * 我们还会得到若干个大于M的结果,但我们只需要第一个大于M的结果,因为我们希望丑数是按从小到大顺序生成的,其他更大的结果我们以后再说。
 * 我们把得到的第一个乘以2后大于M的结果,记为M2。
 * 同样我们把已有的每一个丑数乘以3和5,能得到第一个大于M的结果M3和M5。
 * 那么下一个丑数应该是M2、M3和M5三个数的最小者。
 *
 *
 *前面我们分析的时候,提到把已有的每个丑数分别都乘以2、3和5,事实上是不需要的,
 *因为已有的丑数是按顺序存在数组中的。对乘以2而言,肯定存在某一个丑数T2,
 *排在它之前的每一个丑数乘以2得到的结果都会小于已有最大的丑数,在它之后的每一个丑数乘以2得到的结果都会太大。
 *我们只需要记下这个丑数的位置,同时每次生成新的丑数的时候,去更新这个T2。
 * 对乘以3和5而言,存在着同样的T3和T5。
 *
 * 大智小结: 1.  任何一个丑数 都是 2、3、5的倍数
 *           2.  获得 一个丑数需要比较 三个数字  m2 ,m3,m5 。而m2 ,一定是上一个 m2 的两倍关系。

你可能感兴趣的:(面试题,剑指offer-java实现)