def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
return sorted(arr)[:k]
sorted()内部的排序方法为归并排序
时间复杂度O(nlogn) 空间复杂度O(logn)
求最小k个数用最大堆,求最大k个数用最小堆。
堆是有序排列的完全二叉树,最大堆为根节点为最大值,且父节点比子节点的值大;最小堆为根节点为最小值,且父节点比子节点的值小。
在求最大的k个数时,首先构建一个有k个节点的最小堆,根节点为最小值,然后每新进来一个数,则与根节点比较,若比根节点大,则将该点推入堆,将堆中的最小值点(根节点)推出。遍历完之后,留在堆里的就是最大的k个。
python内置有最小堆库,heapq
heapq.heapify(list)
将list转换为最小堆形式
heapq.heappop(heap)
将heap的最小值推出
heapq.heappush(heap,x)
将x推入heap中
heapq.replace(heap,x)
将x推入,同时将heap中最小元素推出
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
if k==0:
return []
hp=arr[:k]
heapq.heapify(hp)
for i in range(k,len(arr)):
if hp[0]<arr[i]:
heapq.heapreplace(hp,arr[i])
return hp
时间复杂度O(nlogk),空间复杂度O(k).
节点为k的堆的插入删除的时间复杂度为O(logk),循环n次,最坏情况每次循环都需要插入,所以时间复杂度为O(nlogk).
若求最小的k个数,则需要用最大堆。但python内置只有最小堆,因此对数组取反。数组的最大值取相反数后就变成最小值存入根节点中。
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
if k==0:
return []
hp=[-i for i in arr[:k]]
heapq.heapify(hp)
for i in range(k,len(arr)):
if -hp[0]>arr[i]:
heapq.heapreplace(hp,-arr[i])
return [-i for i in hp]
快速选择为快速排序的变种,快速选择通过找到分割点所在位置,然后分别对分割点的左边和右边进行迭代。快速选择只迭代一边,k在哪边就迭代那边,另一边k之后的值不输出,因此不需要排序。当分割点为k时,则分割点左边的就是最小的k个数。
最小的k个数
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
def findkmin(alist,start,end,k):
low=start
high=end
index=random.randint(low,high) #随机取分隔值
alist[index],alist[low] = alist[low],alist[index]
mid_value=alist[low]
while low<high:
while low<high and alist[high] >= mid_value:
high -= 1
alist[low] = alist[high]
while low<high and alist[low] <= mid_value:
low += 1
alist[high] = alist[low]
alist[low] = mid_value
if low == k-1:
return alist[:k]
elif low > k-1:
return findkmin(alist,start,low-1,k)
else:
return findkmin(alist,low+1,end,k)
if k==0:
return []
return findkmin(arr,0,len(arr)-1,k)
最大的k个数
def findKthLargest(self, nums: List[int], k: int) -> int:
def findkmax(alist,start,end,k):
low=start
high=end
index=random.randint(low,high)
alist[index],alist[low] = alist[low],alist[index]
mid_value=alist[low]
while low<high:
while low<high and alist[high] >= mid_value:
high -= 1
alist[low] = alist[high]
while low<high and alist[low] <= mid_value:
low += 1
alist[high] = alist[low]
alist[low] = mid_value
if low == len(alist)-k:
return alist[-k:]
elif low > len(alist)-k:
return findkmax(alist,start,low-1,k)
else:
return findkmax(alist,low+1,end,k)
if k==0:
return []
return findkmax(nums,0,len(nums)-1,k)
时间复杂度平均为O(n),最坏为O(n2)
空间复杂度平均为O(logn),最坏为O(n)