Java中使用PriorityQueue的第k个最小数字的时间复杂度

Posted

技术标签:

【中文标题】Java中使用PriorityQueue的第k个最小数字的时间复杂度【英文标题】:Time complexity of k-th smallest number using PriorityQueue in Java 【发布时间】:2019-03-15 19:37:32 【问题描述】:

我正在尝试解决流行的面试问题Find the k-th smallest number in an array of distinct integers。我看了一些解决方案,发现堆数据结构非常适合这个问题。

因此,我尝试使用 Collections 框架的PriorityQueue 类来实现一个解决方案,假设它在功能上与堆相同。

这是我尝试过的代码:

public static int getKthMinimum(int[] input, int k)
    PriorityQueue<Integer> heap = new PriorityQueue<Integer>();

    // Total cost of building the heap - O(n) or O(n log n) ?
    for(int num : input)
        heap.add(num);      // Add to heap - O(log n)
    

    // Total cost of removing k smallest elements - O(k log n) < O(n) ?
    while(k > 0)
        heap.poll();        // Remove min - O(log n)
        k--;
    
    return heap.peek();     // Fetch root - O(1) 

基于docs,poll 和 add 方法需要 O(log n) 时间,而 peek 需要恒定时间。

    while 循环的时间复杂度是多少? (我认为 O(k log n))。 就本问题而言,是否应将 O(k log n) 视为高于 O(n)?是否有切换的阈值? 这段代码的总时间复杂度是多少?会是 O(n) 吗? 如果还不是 O(n),有没有办法在 O(n) 中解决它,同时使用 PriorityQueue 类?

【问题讨论】:

【参考方案1】:

1。 while 循环的时间复杂度是多少? (我认为 O(k log n))。

O(k log n) 是正确的。

2。出于这个问题的目的,是否应该将 O(k log n) 视为高于 O(n)?有没有切换的门槛?

你不能这样假设。 k 可以是 0 到 n-1 之间的任意值,这意味着 k log n 可以是 0 之间的任意值到 n 记录 n

3。这段代码的总时间复杂度是多少?会是O(n)吗?

O(n log n),因为这是构建堆的成本。

可以在 O(n) 时间内构建一个堆,但您的代码不会这样做;如果是这样,那么您的总复杂度将是 O(n + k log n) 或者,等效地,O(MAX(n, k log n))。

4。如果还不是 O(n),有没有办法在 O(n) 中解决它,同时使用 PriorityQueue 类?

没有。在最坏情况O(n) 时间存在selection algorithms,但它们有点复杂,它们不使用PriorityQueue

最快的基于PriorityQueue 的解决方案需要 O(MAX(n, n log MIN(k em>, n-k))) 时间。 (关键是在迭代时只保留堆中 k 个最小的元素——或者 n-k 个最大的元素并使用 max-堆,如果 k 足够大,值得这样做。)

【讨论】:

以上是关于Java中使用PriorityQueue的第k个最小数字的时间复杂度的主要内容,如果未能解决你的问题,请参考以下文章

背包专题A - Bone Collector II hdu2639 01背包的第k个最优解

java - 如何使用PriorityQueue集合从Java中的给定数组在O(n)时间内构建最大堆?

热题100_20230510

LeetCode 378. 有序矩阵中第K小的元素 Java

计算机程序的思维逻辑 (47) - 堆和PriorityQueue的应用

最大堆中的第 K 个最大元素