Algorithm 在O(N+;K)时间内从N个整数的数组中提取K个最大元素

Algorithm 在O(N+;K)时间内从N个整数的数组中提取K个最大元素,algorithm,data-structures,time-complexity,Algorithm,Data Structures,Time Complexity,所以,我们有一个N个整数的列表,从中我们想要得到K个最大的整数(未排序)。 问题是,这需要能够在O(N+K)中运行。这就是作业中所说的 我检查了各种算法,甚至自己做了,但我能得到的最好结果是O((n-k)*k),其中 除非我错了,否则我不认为它接近O(N+K) 假设列表中的值几乎是随机的,并且都是正的,有没有算法可以在O(N+K)中实现这一点?(我们不知道他们能达到的最大值) 注意,我需要从N,K个整数中找到K个最大整数,而不是第K个最大整数 示例:N=5,K=2 输入:56893 输出:9 8

所以,我们有一个N个整数的列表,从中我们想要得到K个最大的整数(未排序)。 问题是,这需要能够在O(N+K)中运行。这就是作业中所说的

我检查了各种算法,甚至自己做了,但我能得到的最好结果是O((n-k)*k),其中 除非我错了,否则我不认为它接近O(N+K)

假设列表中的值几乎是随机的,并且都是正的,有没有算法可以在O(N+K)中实现这一点?(我们不知道他们能达到的最大值)

注意,我需要从N,K个整数中找到K个最大整数,而不是第K个最大整数

示例:N=5,K=2 输入:56893
输出:9 8

使用选择算法查找第k个最大元素。 是一种O(n)选择算法

因此,对于您的问题,有一个简单的O(n)算法: 让
KTH
成为选择算法返回的第k个最大元素。这需要O(n)个时间。 扫描阵列并提取所有元素>=
KTH
。这需要O(n)个时间


Quickselect是另一个值得了解的选择算法。它基于快速排序,所以在平均情况下只有O(n)

这个想法是,创建一个二元搜索树,可以在O(logn)中完成,但在最坏的情况下O(n)[其中n-是这种情况下的总节点/数组元素]

现在我们可以进行顺序遍历,以获得所有元素的排序顺序,这可以通过O(N)[Proof:]

现在遍历已排序的元素K次(降序)

因此,总体复杂度为:O(N)+O(N)+O(K)=>O(N+K)

实施:

public class Solution{
static class BST{
    int val;
    BST left, right;

    public BST(int val) {
        this.val = val;
        this.left = this.right = null;
    }
}
// making bst from the array elements
static BST add(BST root, int item) {
    if(root == null) return new BST(item);

    if(root.val > item)
        root.left = add(root.left, item);

    else root.right = add(root.right, item);

    return root;
}
// doing inorder to get all elements in sorted order
static void inorder(BST root, List<Integer> list) {
    if(root.left != null)
        inorder(root.left, list);

    list.add(root.val);

    if(root.right != null)
        inorder(root.right, list);

}
public static void main(String[] args) {
    //Example: N = 5, K = 2 Input: 5 6 8 9 3 Output: 9 8
    int [] a = {1, 9, 2, 7, 3, -1, 0, 5, 11};

    BST root = null;

    for(int i=0; i<a.length; i++) {
        root = add(root, a[i]);
    }
    List<Integer> list = new ArrayList<Integer>();
    inorder(root, list);

   // process the list K times, to get K-th largest elements        
}
公共类解决方案{
静态类BST{
int-val;
BST左,右;
公共BST(内部val){
this.val=val;
this.left=this.right=null;
}
}
//从数组元素生成bst
静态BST添加(BST根,int项){
如果(root==null)返回新的BST(项);
如果(root.val>项)
root.left=添加(root.left,项);
else root.right=添加(root.right,项);
返回根;
}
//按排序顺序获取所有元素
静态无效索引(BST根目录、列表){
if(root.left!=null)
顺序(root.left,list);
list.add(root.val);
if(root.right!=null)
顺序(root.right,list);
}
公共静态void main(字符串[]args){
//示例:N=5,K=2输入:5 6 8 9 3输出:9 8
int[]a={1,9,2,7,3,-1,0,5,11};
BST root=null;

对于(int i=0;i可能是它的重复项,用于查找第k个最大元素,我是否必须执行此算法k次才能从N中得到前k个最大整数?因为我需要倍数,其中k表示有多少。这不是仍然是O(N*k)吗?否。请参见答案中的第二段。插入到树中是(摊销)
O(logn)
,但您正在插入
N
元素,因此总构建时间是
O(N log N)
。然后执行
O(N)
更多操作以将项目从树中拉出并放入列表,然后执行
O(K)
操作以再次从列表中取出值。因此时间将是
O(N log N+N+K)
或者,简化,
O(N log N+K)