topk问题解决思路

topk问题解决方法

顾名思义,topk问题就是求解最大或者最小k个数字的一类问题

常见的解决思路是先排序,然后取依次取k个,最大堆/最小堆,

排序法

思路:先进行排序然后依次取k个,本次讲都是取topk大

def q_sort(ary, left, right):
    if left<=right:
    
        ary[right],ary[left] = ary[left],ary[right]
        store = left
        for i in range(left,right):
            if ary[i] >= ary[right]:
                ary[store],ary[i] = ary[i],ary[store]
                store+=1
        ary[store],ary[right] = ary[right],ary[store]
        q_sort(ary,left,store-1)
        q_sort(ary,store+1,right)

def topk_sort(ary, k):
    q_sort(ary,0,len(ary)-1)
    return ary[:k]

复杂度: 快排是nlogn, 取k个, 所以最终的时间复杂度是O(nlogn)

最小堆

tips:求最大用最小堆,求最小用最大堆
思路,先使用前k个元素,建立一个最小堆,然后不断与堆顶元素进行比较

def build_heap(ary):
    #建立堆
    for i in range(len(ary)//2,-1,-1):
        adjust_heap(ary,i,len(ary))

def adjust_heap(ary, i, size):
    #调整堆
    left = 2*i + 1
    right = 2*i + 2
    min_index = i
    if left<size and ary[left]<ary[min_index]:
        min_index = left 
    if right<size and ary[right]<ary[min_index]:
        min_index = right 

    if min_index!=i:
        ary[min_index],ary[i] = ary[i],ary[min_index]
        adjust_heap(ary,min_index,size)

def topk_heap(ary,k):
    if len(ary)<k:
        return []
    
    heap = ary[:k]
    build_heap(heap)
    for i in range(k,len(ary)):
        if ary[i]>heap[0]:
            heap[0] = ary[i]
            adjust_heap(heap,0,len(heap))
    return heap

由于堆本地上是一颗二叉搜索树,因此每次调整时间复杂度都是O(logk) 注意是logk。 因为堆大小只有k,同时会进行n次调整,因此算法时间复杂度为O(nlogk)

改进快排(又称随机选择)

考虑到求解的是topk问题,有一个直观的思想就是只排序前k个,是不是就可以解决topk的问题啦

按着这种想法,我们改造快速排序,使其只排前k个元素

考虑两种情况

  1. k刚好为位于pivot的左边,那么只需要继续排序[left:k]
  2. 当k位于pivot的右边时,我们需要继续排序ary[pivot+1,right]
def quick_select(ary,left,right, k):
    if left<=right:
        ary[left],ary[right] = ary[right],ary[left]
        store = left 
        for i in range(left,right):
            if ary[i]>=ary[right]:
                ary[store],ary[i] =ary[i],ary[store]
                store+=1
        ary[store],ary[right] = ary[right],ary[store]
        if k<=store:
            quick_select(ary,left,store-1,k)
        else:
            quick_select(ary,store+1,right,k)

def topk_quick(ary,k):
    quick_select(ary,0,len(ary)-1,k)
    return ary[:k]

考虑时间复杂度, quick_select本质上一个二分法,因此复杂度时logn, 被会调用k次(之际应该小于k),简单标记为O(klogn).

练习

https://leetcode-cn.com/problems/top-k-frequent-elements/submissions/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值