时间限制超过最大堆

Time Limit Exceed about max heap

本文关键字:时间      更新时间:2023-10-16

我想设计一个功能,以在一组无序的n个元素中找到k最大的元素,并具有时间复杂性:在线法官上的 Θ(N+klogN)

这是一个样本:


输入

LN 1 : N K
LN 2 : N numbers

输出

LN 1 : K biggest number
LN 2 : Final heap

样品输入

10 4
17 19 26 37 30 11 5 29 32 1

样本输出

29
26 19 11 17 1 5

这是我的代码:

#include <iostream>
using namespace std;
int main(){
    int i,j,rc,temp,temp1,length,K;
    cin>>length>>K;
    int *heap = new int[length];
    for(i=0;i<length;i++) cin>>heap[i];
    for(i=length/2-1;i>=0;i--){                  //build a max heap first with Θ(N)
        while(!((i>=length/2)&&(i<length))){
            j = 2*i+1;
            rc = 2*i+2;
            if((rc<length)&&(heap[j]<heap[rc])) j=rc;
            if(heap[i]>heap[j]) break;
            temp = heap[i];
            heap[i]=heap[j];
            heap[j]=temp;
            i=j;
        }
    }
    int k,n=length;
    for(k=0;k<K;k++){                         //shiftdown k times to find k biggest 
        temp1=heap[--n];                      //numbers with Θ(klogN)
        heap[n] = heap[0];
        heap[0] = temp1;
        if(n!=0) {
            i=0;
                while(!((i>=n/2)&&(i<n))){
                     j = 2*i+1;
                    rc = 2*i+2;
                    if((rc<n)&&(heap[j]<heap[rc])) j=rc;
                    if(heap[i]>heap[j]) break;
                    temp = heap[i];
                    heap[i]=heap[j];
                    heap[j]=temp;
                    i=j;
                }
            }
        }

    cout<<heap[length-K]<<endl;
    for(i=0;i<length-K;i++)
        cout<<heap[i]<<" ";
    return 0;
}

没关系,但是数据之一超过了时间限制,我对如何解决此问题感到非常困惑。

您的筛选操作似乎不正确。那里不应该有两个嵌套环。您应该只是从根本上开始,并继续与其中一个孩子交换,直到它比这两个孩子大。外循环for(i=n/2-1;i>=0;i--)不应该在那里(这会导致每个筛分降低O(n)) - 我认为您应该将i设置为0。

编辑:您的堆操作也太慢了:您正在使用相同的循环变量i用于外部和内部循环,因此它会交替生长更大和较小。内环应从外循环的i开始,但不应影响外环的下一次迭代中i的值。我建议将筛选操作放在自己的功能中。这既可以解决此问题,又避免对筛选两次编码。

我猜一些在线judge.org竞赛。您为什么不共享问题链接?

那么,我们可能可以分辨您是否真的需要Heapsort,或者您是否会更好地使用QuickSelect和良好的启发式方法。

我的猜测是,普通的heaport将在其测试用例之一中不够。

您可能还需要添加优化,例如在开始和结束时检查预分类数据或反向排序的数据(和数据部分)。避免为这些部分构建堆,但要保持原样。

尝试在巨大 reverse 排序列表上运行heapsort ,带有大k,iirc,这是一个最坏的情况(对于最大速度,任何米哈最糟糕的情况,反之亦然)。

典型的在线法官测试案例通常是围绕这种已知最坏情况的精心设计的。然后设置时间限制,以便即使使用非常好的优化O(n + k log n)解决方案,您将丢失的解决方案与真正的O(n)解决方案相比。他们只需要使K足够大。他们来自比赛,他们想通过给他们真正的均值输入文件来挑战他们!

P.S。您 HEAP BUILD 似乎也太复杂了。问题是您再次增加i 。您不需要这样做。通过在同时循环中增加I,您会导致自下而上的堆构造再次"重新启动"多次"重新启动"。因此,您的堆构建可能不再是O(n)

您可能想检查三个差异序列发生的事情:

    1. 4 2 1 2 3 4
    1. 4 2 4 3 2 1
    1. 4 2 1 1 1 1

 int NN=0;
 for(i=length/2-1;i>=0;i--){                  //build a max heap first with Θ(N)
cout << "i=" << i << "n";
    while(!((i>=length/2)&&(i<length))){
        j = 2*i+1;
        rc = 2*i+2;
        cout << NN++ << " " << j << " " << rc << " " << i << "n";
        if((rc<length)&&(heap[j]<heap[rc])) j=rc;
        if(heap[i]>heap[j]) break;
        temp = heap[i];
        heap[i]=heap[j];
        heap[j]=temp;
        i=j;
    }
}

在最后一个情况下,环将稳定为j = 3;RC = 4;i = 1;

也许内部循环应该使用单独的变量代替" i"。