[英]Time limit excedded for program - find Kth smallest element
I am looking at GeeksForGeeks problem Kth smallest element :我正在查看 GeeksForGeeks 问题第 K 个最小元素:
Given an array arr[] and an integer K where K is smaller than size of array, the task is to find the Kth smallest element in the given array.
给定一个数组arr[]和一个整数K ,其中 K 小于数组的大小,任务是找到给定数组中第 K 个最小的元素。 It is given that all array elements are distinct.
假设所有数组元素都是不同的。
Expected Time Complexity: O(n)
预期时间复杂度: O(n)
Expected Auxiliary Space: O(log(n))预期辅助空间: O(log(n))
Constraints:约束:
1 <= N <= 1051 <= N <= 105
1 <= arr[i] <= 1051 <= arr[i] <= 105
1 <= K <= N1 <= K <= N
class Solution:
def kthSmallest(self,arr, l, r, k):
'''
arr : given array
l : starting index of the array i.e 0
r : ending index of the array i.e size-1
k : find kth smallest element and return using this function
'''
arr2=arr[:k]
arr2.insert(0,None)
for i in range(k//2,0,-1):
arr2=self.heapify(arr2,i,k-1)
for i in arr[k:]:
if i <arr2[1]:
arr2[1]=i
arr2=self.heapify(arr2,1,k-1)
return arr2[1]
def heapify(self,arr, i, r):
if 2 * i <= r + 1 and arr[2 * i] > arr[i]:
arr[2 * i], arr[i] = arr[i], arr[i * 2]
arr = self.heapify(arr, 2 * i, r)
if 2 * i + 1 <= r + 1 and arr[2 * i + 1] > arr[i]:
arr[2 * i + 1], arr[i] = arr[i], arr[i * 2 + 1]
arr = self.heapify(arr, 2 * i + 1, r)
return arr
I made a sub array of first K elements in the array, and max heapified it.我在数组中创建了一个包含前 K 个元素的子数组,并对其进行了最大处理。 Then for the rest of the elements in the array, if the element is smaller than the first element of the heap, I replaced the top element and then max heapified the top element.
然后对于数组中的其余元素,如果该元素小于堆的第一个元素,我替换了顶部元素,然后将顶部元素最大化。 I am getting time limit exceeded error.
我收到超出时间限制的错误。 Any idea?
任何想法?
The problem is that your heapify
function is not efficient.问题是您的
heapify
函数效率不高。 In the worst case it makes two recursive calls at the same recursion depth.在最坏的情况下,它会以相同的递归深度进行两次递归调用。 This may even happen at several recursion depths, so that the number of times
heapify
is called recursively could become quite large.这甚至可能发生在几个递归深度,因此递归调用
heapify
的次数可能会变得非常大。 The goal is to have this only call heapify
once (at the most) per recursion level.目标是让每个递归级别只调用一次
heapify
(最多)。
It should first find the greatest child, and only then determine whether heapify
should be called again, and make that single call if needed.它应该首先找到最大的孩子,然后才确定是否应该再次调用
heapify
,并在需要时进行单次调用。
Some other remarks:其他一些评论:
Instead of making heapify
recursive, use an iterative solution.与其使
heapify
递归,不如使用迭代解决方案。 This will also save some execution time.这也将节省一些执行时间。
It is strange to pass k-1
to heapify
as last argument, when the last element sits at index k
, and so you get the weird comparison <= r + 1
in that function.当最后一个元素位于索引
k
处时,将k-1
作为最后一个参数传递给heapify
很奇怪,因此您在该函数中得到了奇怪的比较<= r + 1
。 It is more intuitive to pass k
as argument, and work with <= r
inside the function.将
k
作为参数传递更直观,并在函数内部使用<= r
。
As arr
is mutated by heapify
it is not needed to return it.由于
arr
被heapify
突变,因此不需要返回它。 This is just overhead that is useless.这只是无用的开销。
2 * i
is calculated several times. 2 * i
被计算了几次。 It is better to calcuate this only once.最好只计算一次。
arr[k:]
makes a copy of that part of the list. arr[k:]
复制列表的该部分。 This is not really needed.这并不是真正需要的。 You could just iterate over the range and take the corresponding value from the array in the loop.
您可以迭代范围并从循环中的数组中获取相应的值。
It is not clear why the main function needs to get l
and r
as arguments, since in comments it is explained that l
will be 0 and r
the index of the last element.不清楚为什么 main 函数需要获取
l
和r
作为参数,因为在注释中解释了l
将是 0 并且r
是最后一个元素的索引。 But in my opinion, since you get them, you should use them.但在我看来,既然你得到了它们,你就应该使用它们。 So you should not assume
l
is 0,... etc.所以你不应该假设
l
是 0,... 等等。
I would use a more descriptive name for arr2
.我会为
arr2
使用更具描述性的名称。 Why not name it heap
?为什么不将其命名为
heap
?
Here is the improvement of your code:这是您的代码的改进:
class Solution:
def kthSmallest(self,arr, l, r, k):
'''
arr : given array
l : starting index of the array i.e 0
r : ending index of the array i.e size-1
k : find kth smallest element and return using this function
'''
heap = [arr[i] for i in range(l, r + 1)]
heap.insert(0, None)
for i in range(k//2, 0, -1):
self.heapify(heap, i, k)
for i in range(l + k, r + 1):
val = arr[i]
if val < heap[1]:
heap[1] = val
self.heapify(heap, 1, k)
return heap[1]
def heapify(self, arr, i, r):
child = 2 * i
while child <= r:
if child + 1 <= r and arr[child + 1] > arr[child]:
child += 1
if arr[child] <= arr[i]:
break
arr[child], arr[i] = arr[i], arr[child]
i = child
child = 2 * i
Finally, there is a heapq
module you can use, which simplifies your code:最后,您可以使用一个
heapq
模块,它可以简化您的代码:
from heapq import heapify, heapreplace
class Solution:
def kthSmallest(self, arr, l, r, k):
'''
arr : given array
l : starting index of the array i.e 0
r : ending index of the array i.e size-1
k : find kth smallest element and return using this function
'''
heap = [-arr[i] for i in range(l, l + k)]
heapify(heap)
for i in range(l + k, r + 1):
val = -arr[i]
if val > heap[0]:
heapreplace(heap, val)
return -heap[0]
The unary minus that occurs here and there is to make the native minheap work as a maxheap.在这里和那里发生的一元减号是为了使本机 minheap 作为 maxheap 工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.