取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

posted @ 2020-01-05 20:59  Assange  阅读(260)  评论(0编辑  收藏  举报