zoukankan      html  css  js  c++  java
  • 丑数

    题目描述

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


    思路

    丑数:只包含质因子2、3、5的数称作丑数。(说通俗点:一个数的所有因子中,为质数的因子只能是2、3、5)

    关键点(难点):丑数p = 2 ^ x * 3 ^ y * 5 ^ z;

    即每个丑数都满足上述式子,只是x、y、z取值不同生成了不同的丑数,

    同时得出一个丑数p1一定是由另一个小于它的丑数p2乘以2 or 乘以3 or 乘以5得到的。

    如:

    1. 1是最小(也是最初的丑数),于是我们分别将1与2、3、5相乘→得到2、3、5三个丑数;
    2. 然后由2、3、5出发我们又会得到:4,6,10,6,9,15,10,15,25九个丑数;
    3. ……

    但是这样得到的丑数是有重复且无序的,题目要求我们求按从小到大的顺序的第N个丑数,即要求我们得出的丑数是有序排列的(升序)。

    那么:

    • 先定义一个队列a用来存储丑数,a[0]=1;

    • 当由1得出2、3、5三个丑数时,我们可以取新生成的丑数中最小的丑数:2,然后2加入队列a,即a={1,2};

    • 紧接着我们由a[1]=2与2、3、5相乘得出新丑数:4、6、10,注意:此时4并不是当前的最小丑数,不要忘了第二部生成的3和5,因此,我们可以维护3个数列;

    • 假设有3个数列,分别为: 乘以2产生的丑数队列、 乘以3产生的丑数队列、 乘以5产生的丑数队列;

      (1)丑数数组: 1

      *乘以2的队列:2

      *乘以3的队列:3

      *乘以5的队列:5

      选择三个队列头最小的数2加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;


      (2)丑数数组:1,2

      *乘以2的队列:4

      *乘以3的队列:3,6

      *乘以5的队列:5,10

      选择三个队列头最小的数3加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;


      (3)丑数数组:1,2,3

      *乘以2的队列:4,6

      *乘以3的队列:6,9

      *乘以5的队列:5,10,15

      选择三个队列头里最小的数4加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;


      (4)丑数数组:1,2,3,4

      *乘以2的队列:6,8

      *乘以3的队列:6,9,12

      *乘以5的队列:5,10,15,20

      选择三个队列头里最小的数5加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;


      (5)丑数数组:1,2,3,4,5

      *乘以2的队列:6,8,10,

      *乘以3的队列:6,9,12,15

      *乘以5的队列:10,15,20,25

      选择三个队列头里最小的数6加入丑数数组,但我们发现,有两个队列头都为6,所以我们弹出两个队列头,同时将12,18,30放入三个队列;

      ……………………

      疑问:

      1.为什么分三个队列?

      丑数数组里的数一定是有序的,因为我们是从丑数数组里的数乘以2,3,5选出的最小数,一定比以前未乘以2,3,5大,同时对于三个队列内部,按先后顺序乘以2,3,5分别放入,所以同一个队列内部也是有序的;

      2.为什么比较三个队列头部最小的数放入丑数数组?

      因为三个队列是有序的,所以取出三个头中最小的, 大专栏  丑数等同于找到了三个队列所有数中最小的。

      实现思路:

      我们没有必要维护三个队列只需要记录三个指针显示到达哪一步;“|”表示指针,arr表示丑数数组;

      (1)1

      |2

      |3

      |5

      目前指针指向0,0,0,队列头arr[0] * 2 = 2, arr[0] 3 = 3, arr[0] 5 = 5

      (2)1 2

      2 |4

      |3 6

      |5 10

      目前指针指向1,0,0,队列头arr[1] * 2 = 4, arr[0] 3 = 3, arr[0] 5 = 5

      (3)1 2 3

      2| 4 6

      3|6 9

      |5 10 15

      目前指针指向1,1,0,队列头arr[1] * 2 = 4, arr[1] 3 = 6, arr[0] 5 = 5

      ………………

    代码:

    import java.util.List;
    import java.util.ArrayList;
    import java.util.Scanner;

    public class {
    public static void main(String[] args) {
    Scanner in=new Scanner(System.in);
    int N=in.nextInt();
    int num=GetUglyNumber_Solution(N);
    System.out.println(num);
    }

    public static int GetUglyNumber_Solution(int N) {
    if(N<=0) return 0;
    List<Integer> list=new ArrayList<Integer>();
    list.add(1);
    int i1=0,i2=0,i3=0;
    while(list.size()<N) {
    int n1=list.get(i1)*2;
    int n2=list.get(i2)*3;
    int n3=list.get(i3)*5;
    int min=Math.min(n1, Math.min(n2, n3));
    list.add(min);
    if(min==n1) {
    i1++;
    }
    if(min==n2) {
    i2++;
    }
    if(min==n3) {
    i3++;
    }
    }
    return list.get(N-1);
    }
    }

    运行时间:26ms

    占用内存:9468k

    参考思路:https://www.nowcoder.com/questionTerminal/6aa9e04fc3794f68acf8778237ba065b


  • 相关阅读:
    973. K Closest Points to Origin
    919. Complete Binary Tree Inserter
    993. Cousins in Binary Tree
    20. Valid Parentheses
    141. Linked List Cycle
    912. Sort an Array
    各种排序方法总结
    509. Fibonacci Number
    374. Guess Number Higher or Lower
    238. Product of Array Except Self java solutions
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12032697.html
Copyright © 2011-2022 走看看