丑数 II

194 阅读2分钟

题目

给你一个整数 n ,请你找出并返回第 n 个 丑数 。

丑数 就是只包含质因数 23 和/或 5 的正整数。

思路

返回第n个丑数,首先想到的就是最小堆。堆这种数据结构通常可以被看做一棵树的数组对象。它没有使用父指针或者子指针。堆根据“堆属性”来排序。题目中构建一个最小堆,第n次从堆中移出的数据就是排行第n的数据。

特性和作用

特性:

  • 堆中某个结点的值总是不大于或不小于其父结点的值;
  • 堆总是一棵完全二叉树。

作用:

  • 快速找出一个集合中的最小值(或者最大值)-topk问题
  • 构建优先队列
  • 排序

实例: 假设有个这样的数据

10, 14, 25, 33, 81, 82, 99

一个从低到高有序排列的数组是以有效的最小堆,我们可以将这个堆画出来:

堆属性适用于每一个节点,因为父节点总是比它的字节点小。

注意: 并不是每一个最小堆都是一个有序数组!要将堆转换成有序数组,需要使用堆排序。

使用: 在java中通常会用优先队列(PriorityQueue)来构建二叉堆。PriorityQueue是继承AbstractQueue,AbstractQueue实现了Queue,继承了AbstractCollection。

PriorityQueue (Java Platform SE 8 )

  • Modifier and TypeMethod and Description
    booleanadd(E e)将指定的元素插入到该优先级队列中。
    voidclear()从这个优先级队列中移除所有的元素。
    Comparator<? super E>comparator()返回用于为该队列中的元素的比较,或 null如果这个队列是根据其元素的 natural ordering排序。
    booleancontains(Object o)返回 true如果此队列包含指定的元素。
    Iterator<E>iterator()返回此队列中元素的迭代器。
    booleanoffer(E e)将指定的元素插入到该优先级队列中。
    Epeek()检索,但不删除,这个队列头,或返回 null如果队列为空。
    Epoll()检索并移除此队列的头,或返回 null如果队列为空。
    booleanremove(Object o)从该队列中移除指定元素的一个实例,如果它是存在的。
    intsize()返回此集合中的元素的数目。
    Spliterator<E>spliterator()创建一个后期绑定和快速失败 Spliterator在队列中的元素。
    Object[]toArray()返回一个包含此队列中所有元素的数组。
    <T> T[]toArray(T[] a)返回包含此队列中的所有元素的数组;返回数组的运行时类型是指定的数组的运行时类型。

代码实现

public static int nthUglyNumber(int n) {
    int[] factors = {2, 3, 5};
    Set<Long> set = new HashSet<Long>();
    PriorityQueue<Long> minHeap = new PriorityQueue<Long>();
    set.add(1L);
    minHeap.offer(1L);
    int topK = 0;
    for (int i = 0; i < n; i++) {
        long curr = minHeap.poll();
        topK = (int) curr;
        for (int factor : factors) {
            long next = curr * factor;
            if (set.add(next)) {
                minHeap.offer(next);
            }
        }
    }
    return topK;
}

链接:leetcode-cn.com/problems/ug… git: gitee.com/zhwgit/java…