我想设计一个函数来查找时间复杂度为无序的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;
}
没关系,但其中一个数据是Time Limit Exceed,我对如何解决这个问题感到很困惑。
答案 0 :(得分:0)
您的筛选操作似乎不正确。那里不应该有两个嵌套循环。你应该从根开始,并与其中一个孩子交换,直到它比两者都大。外部循环for(i=n/2-1;i>=0;i--)
不应该在那里(它导致每次筛选取O(n)
) - 我认为你应该将i
设置为0以从根开始。
编辑:你的heapify操作也太慢了:你对外部和内部循环使用相同的循环变量i
,因此它会交替变大和变小。内循环应该以外循环的i
开始,但不应该影响外循环下一次迭代中i
的值。我建议将sift-down操作放在自己的函数中。这既可以解决这个问题,也可以避免两次扫描编码。
答案 1 :(得分:0)
我猜想有些在线judge.org比赛。你为什么不分享问题链接?
然后我们可以判断你是否真的需要heapsort,或者你是否更喜欢使用QuickSelect和良好的启发式方法。
我的猜测是,对于他们的一个测试用例,一个普通的heapsort 不足。
您可能还需要添加优化,例如检查预分类数据,或者在开头和结尾反转已排序的数据(和数据部分)。避免为这些部分构建堆,但要保持原样。
尝试在巨大的反向排序列表上运行heapsort,使用大k,IIRC这是最坏的情况(对于最大堆,任何最小堆都应该是最糟糕的情况,反之亦然)。
典型的在线判断测试案例通常围绕这些已知的最坏情况进行设计。然后设置时间限制,以便即使使用非常好的优化O(n + k log n)
解决方案,与真正的O(n)
解决方案相比也会失败。他们只需要让k足够大。他们来自竞赛,他们希望通过给予真实的平均输入文件来挑战人们!
P.S。您堆构建似乎也太复杂了。问题是您再次增加i
。你不应该这样做。通过在while循环中增加i,可以使自下而上的堆构造再次“重新启动”多次。所以你的堆构建可能不再是O(n)
。
答案 2 :(得分:0)
您可能想要检查三个差异序列会发生什么:
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'。