• TopK问题代码(Python,Java)


    主要有两种方法吧,调用函数的就不用讲了,面试可能会被打。。。主要还是两个经典的算法,一个堆排序,一个是快排的升级版本:快速选择的方法。

    快速选择法

    第一种是快速选择的方法,利用的是快速排序中将分区分成两个部分,那么如果左边分区长度大于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 这个函数,优化的点还是很多的,我就懒得写了。。。大家自己去优化吧。

  • 相关阅读:
    Redis涉及的概念
    Redis高级教程
    Redis基础入门
    Java多线程面试题
    Java集合面试题
    Java集合基础
    Java基础面试题总结
    Zookeeper Basics
    GitLab基础入门
    阿里云ECS服务器Docker安装Tomcat过程记录
  • 原文地址:https://www.cnblogs.com/tjpeng/p/12534804.html
Copyright © 2020-2023  润新知