找到数组中最大(最小)的k个数 python解法
方法一:内置函数sorted()
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)