leetcode
leetcode 2851 ~ 2900
第 k 个数

第 k 个数

难度:

标签:

题目描述

Design an algorithm to find the kth number such that the only prime factors are 3, 5, and 7. Note that 3, 5, and 7 do not have to be factors, but it should not have any other prime factors. For example, the first several multiples would be (in order) 1, 3, 5, 7, 9, 15, 21.

Example 1:

Input: k = 5

Output: 9

代码结果

运行时间: 24 ms, 内存: 16.6 MB


/*
 * 题目思路:
 * 使用Java Stream API同样需要实现最小堆和去重机制。
 * 由于Stream不直接支持优先队列,我们仍然需要结合使用PriorityQueue和HashSet。
 */
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.stream.Stream;

public class KthNumberWithPrimeFactorsStream {
    public int getKthMagicNumber(int k) {
        if (k <= 0) return 0;
        PriorityQueue<Long> minHeap = new PriorityQueue<>();
        HashSet<Long> seen = new HashSet<>();
        long[] primes = {3, 5, 7};
        minHeap.add(1L);
        seen.add(1L);
        long number = 1;
        for (int i = 0; i < k; i++) {
            number = minHeap.poll();
            for (long prime : primes) {
                long newNumber = number * prime;
                if (!seen.contains(newNumber)) {
                    seen.add(newNumber);
                    minHeap.add(newNumber);
                }
            }
        }
        return (int) number;
    }
    public static void main(String[] args) {
        KthNumberWithPrimeFactorsStream solution = new KthNumberWithPrimeFactorsStream();
        System.out.println(solution.getKthMagicNumber(5)); // 输出: 9
    }
}

解释

方法:

该题解使用了最小堆(优先队列)以及哈希集合来求解。首先,1被视为第一个满足条件的数,因此初始化堆和集合都包含这个数。对于每次从堆中弹出的最小数(当前的最小数),将它与3、5、7分别相乘,得到的新数如果之前未出现过,就加入到堆和集合中。这个过程重复k次,最后从堆中弹出的数即为第k个数。

时间复杂度:

O(k log k)

空间复杂度:

O(k)

代码细节讲解

🦆
为什么选择使用最小堆(优先队列)而不是其他数据结构如数组或链表来解决这个问题?
使用最小堆(优先队列)的原因在于该数据结构提供了高效地访问和删除最小元素的能力,这对于本题是必需的,因为我们需要按顺序找到第k个最小的合格数。最小堆能够保证每次从堆顶弹出的总是当前堆中最小的数,这是数组或链表无法高效完成的。如果使用数组,每次寻找最小数需要O(n)时间,使用链表虽然可以在O(1)时间内添加元素,但删除最小元素平均需要O(n)时间。相比之下,最小堆可以在O(log n)时间内完成插入和删除最小元素的操作,更适合解决本题。
🦆
在处理生成的新数时,使用哈希集合来检查元素是否已出现。这种方法的效率如何,是否有可能成为性能瓶颈?
使用哈希集合来检查元素是否已存在是一个效率很高的方法。哈希集合在平均情况下提供O(1)时间复杂度的查找、插入和删除操作。这意味着即使对于大量的数据,哈希集合都能快速响应是否有重复元素的查询。在本题中,考虑到需要频繁地检查和插入新生成的数,使用哈希集合可以显著减少时间开销,相比于其他如列表等需要O(n)时间复杂度的数据结构,哈希集合更有效。因此,哈希集合通常不会成为性能瓶颈。
🦆
题解中提到每次操作都会插入最多三个元素,但堆的最大大小为什么是3k而不是k或更大?
堆的最大大小可能达到3k是因为每次处理时,我们都可能向堆中添加最多三个新的数(当前最小数乘以3、5和7)。即使每次弹出堆顶元素,依然可能在每次迭代中净增加两个元素(如果所有生成的新数都是唯一的)。在进行k次迭代的过程中,最坏的情况是每次迭代都将三个新元素添加到堆中,因此堆的大小可能在某个时刻达到3k。虽然实际情况下由于重复的数不会被重新添加,堆的大小通常会小于这个理论最大值,但为确保算法的正确性和安全性,我们考虑最坏情况下的堆大小。

相关问题