取topK
从小到大取topK个数
方法一:快排的思想,当划分节点的前面刚好为k-1个,把到pivot的值返回就可以了。
1 class Solution: 2 def __init__(self,arr): 3 self.arr = arr 4 def topK(self,k): 5 n = len(self.arr) 6 if k <=0 or k >=n: 7 return [] 8 low = 0 9 high = n-1 10 mid = self.partition(low,high) 11 while k-1 != mid: 12 if k-1 > mid: 13 low = mid+1 14 mid = self.partition(low,high) 15 elif k-1 < mid: 16 high = mid - 1 17 mid = self.partition(low,high) 18 res = self.arr[:mid+1] 19 print(res) 20 21 def partition(self,low,high): 22 pivotKey = self.arr[low] 23 while low < high: 24 while low < high and self.arr[high]>=pivotKey: 25 high-=1 26 self.arr[low],self.arr[high]=self.arr[high],self.arr[low] 27 while low < high and self.arr[low]<=pivotKey: 28 low+=1 29 self.arr[low], self.arr[high] = self.arr[high], self.arr[low] 30 return low 31 32 if __name__ == "__main__": 33 Solution([4,3,6,7,2,8,0,1]).topK(6)
方法二:堆排序
一个很常见的例子,假设我们要选5个最矮的同学参加比赛,候选人选好之后又跑来一个新同学参加评选。这个时候新同学只需要PK候选人中最高的,如果他比最高的还高,就被淘汰,如果比最高的矮,他就可以替代这个最高的。按照这个思想,无论再来多少新同学都可以很快速的选择。
以这个思想为基础,为了最快的找到候选人中最高的,以身高为基准建立大顶堆,每次新人与堆顶PK,PK结束之后维护候选人重新为大顶堆。
这种思想将时间复杂度降到以k为基数,每次调整堆的时间复杂度都是,那么整体时间复杂度为。
1 class Solution2: 2 def topK(self,nums,k): 3 n = len(nums) 4 if k <= 0 or k > n: 5 return [] 6 # 建立大顶堆 7 for i in range((k//2)-1, -1, -1): 8 self.heapAjust(nums,i,k-1) 9 for i in range(k,n): 10 if nums[i]<nums[0]: 11 nums[0],nums[i]=nums[i],nums[0] 12 # 调整前k个数 13 self.heapAjust(nums,0,k-1) 14 print(nums[:k]) 15 def heapAjust(self,nums,start,end): 16 temp = nums[start] 17 # 记录较大的那个孩子下标 18 child = 2 * start + 1 19 while child <= end: 20 # 比较左右孩子,记录较大的那个 21 if child + 1 <= end and nums[child] < nums[child+1]: 22 # 如果右孩子比较大,下标往右移 23 child += 1 24 # 如果根已经比左右孩子都大了,直接退出 25 if temp >= nums[child]: 26 break 27 # 如果根小于某个孩子,将较大值提到根位置 28 nums[start] = nums[child] 29 # 接着比较被降下去是否符合要求,此时的根下标为原来被换上去的那个孩子下标 30 start = child 31 child = child * 2 + 1 32 # 最后将一开始的根值放入合适的位置 33 nums[start] = temp
原文链接:https://blog.csdn.net/qq_20141867/article/details/81152894