找到数组中最大(最小)的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)

你可能感兴趣的:(数据结构与算法)