主要有两种方法吧,调用函数的就不用讲了,面试可能会被打。。。主要还是两个经典的算法,一个堆排序,一个是快排的升级版本:快速选择的方法。
快速选择法
第一种是快速选择的方法,利用的是快速排序中将分区分成两个部分,那么如果左边分区长度大于K,就可以缩小范围,如果左边分区小于K,那么只要在右边的分区中找出剩余的数量就可以了。如果快排熟悉的话,其实还是挺简单的,需要注意的点就是需要随机选择。
import random def partition(nums,left,right): target = nums[left] raw = left left=left+1 while left<= right: while left<=right and nums[right] > target: right -= 1 while left<= right and nums[left] < target: left += 1 if left <= right:#这个需要注意。 nums[left],nums[right] = nums[right],nums[left] nums[raw],nums[left-1] = nums[left-1],nums[raw] return left -1 def randomPartition(nums,left,right): target = random.randint(left,right) #随机取一个数然后交换他们的位置!!不然会出bug nums[target],nums[right] = nums[right],nums[target] pivo = partition(nums,left,right) return pivo def selectMinNum(nums,left,right,k): pivo = randomPartition(nums,left,right) if k == pivo - left + 1: return ; if k < pivo - left+1: selectMinNum(nums,left,pivo-1,k) if k > pivo - left+ 1: selectMinNum(nums,pivo+1,right,k-pivo+left-1) def selectMaxNum(nums,left,right,k): pivo = randomPartition(nums,left,right) if k ==right-pivo+1: return; if k < right-pivo+1: selectMinNum(nums,pivo+1,right,k) if k > right-pivo+1: selectMinNum(nums,left,pivo-1,k-right+pivo-1)
这个还是挺容易的理解的,看代码的话,应该可以看懂,这个是可以直接使用的代码,核心就是在于利用快排和二分的思想,复杂度的话期望是O(N)是不是很神奇呢,详情可以参考算法导论第九章哦.
里面包括两个,求最小的N和最大的N。就是把符号换一下。
堆
使用最大堆和最小堆的思想,每次维护一个容量为k的堆,每次进来一个数,进行堆的改造。将进来的树放在最后,然后从下到上对堆进行改造。
#这个函数是从上到下进行堆的调整 def maxHeapOne(list2,index1): if index1*2+1 <= len(list2)-1: leftChild = index1*2+1 rightChild = index1*2+2 if rightChild > len(list2)-1: if list2[index1] < list2[leftChild]: list2[index1],list2[leftChild] = list2[leftChild],list2[index1] return if list2[index1] > list2[rightChild] and list2[index1] > list2[leftChild]: return if list2[leftChild]> list2[rightChild]: if list2[index1] < list2[leftChild]: list2[index1],list2[leftChild] = list2[leftChild],list2[index1] maxHeapOne(list2,leftChild) if list2[leftChild] < list2[rightChild]: if list2[index1] < list2[rightChild]: list2[index1],list2[rightChild] = list2[rightChild],list2[index1] maxHeapOne(list2,rightChild) #这个函数是从下到上对堆进行调整,前提是其前n-1项为最大堆 def heapUpdate(list2): N = len(list2) cur = N-1 faNode = cur>>1 while faNode >=0: if list2[faNode] > list2[cur]: return if list2[faNode] < list2[cur]: list2[faNode],list2[cur] = list2[cur],list2[faNode] cur = faNode faNode = (faNode-1)>>1 #构建堆 def createHeap(list2): N = len(list2) # cur = N-1 start = (N-1)>>1 while start >= 0:#对最后一个子节点的父节点开始遍历。对每一个节点都构建最大堆。 # print(start) maxHeapOne(list2,start) start -= 1 #获取最大值 def getMax(list2): createHeap(list2) list2[0],list2[-1] = list2[-1],list2[0] res = list2.pop() maxHeapOne(list2,0) #取出最大值后对堆进行调整,从上到下进行调整 return res #minTOPN def getminTop(list2,k): list3 = list2[:k]#先建立一个k的最大堆 createHeap(list3) for i in list2[k:]: # 对后面的元素以此插入,调整堆 list3 +=[i] heapUpdate(list3) list3 = list3[-k:] return list3
最重要的是前两个函数,一个是从上到下对堆进行改造,第二个是从下到上对堆进行改造。其余的函数也是比较容易理解的,当然对于最后一个函数getminTop 这个函数,优化的点还是很多的,我就懒得写了。。。大家自己去优化吧。