topK问题

概述

在N个乱序数字中查找第K大的数字,时间复杂度可以减小至O(N).
可能存在的限制条件:
要求时间和空间消耗最小、海量数据、待排序的数据可能是浮点型等。

方法

方法一

  • 对所有元素进行排序,之后取出前K个元素,时间复杂度高,不提倡。 *
    思路:使用快排,选择排序,堆排序。
    时间复杂度:排序复杂度nlogn,最后要访问第K个元素,因此是O(n*logn)+O(K)=O(n*logn)
    特点:需要对全部元素进行排序,K=1时,时间复杂度也为O(n*logn)。

方法二

  • 只需要对前K个元素排序,剩下N-K个元素不需要排序,时间复杂度高,不提倡。 *
    思路:使用选择排序 或 冒泡排序, 进行K此选择,可得到第K大的数。
    时间复杂度:每一次大循环遍历复杂度是n,共遍历K次,因此是O(n*k)
def selectionSort(arr, k):
    length = len(arr)
    minIndex = 0
    for i in range(length):
        minIndex = i
        for j in range(i+1,length):
            if arr[j] < arr[minIndex]:
                minIndex = j

        arr[i], arr[minIndex] = arr[minIndex], arr[i]
        if i == k:
            return arr[:k]

    return arr

arr = [3,4,9,2,1,0,-10]
print(selectionSort(arr, 3))

方法三

  • 不对前K个数排序+不对N-K个数排序 *
    思路:寻找第K个大元素
    具体方法:使用类似快排,执行一次快排后,每次只选择一部分继续执行快排,直到找到第K个大元素为止,此时这个元素在数组位置后面的元素即所求。
    时间复杂度:
  • 若随机选取枢纽,线性期望时间O(N)
  • 若选取数组的“中位数的中位数”作为枢纽,最坏情况下的时间复杂度O(N)
    利用快排的思想,从数组S中随机找出一个元素X,把数组分为两部分Sa和Sb。Sa中的元素大于等于X,Sb中元素小于X。这时有两种情况:
  1. Sa中元素的个数小于k,则Sb中的第k-|Sa|个元素即为第k大数;
  2. Sa中元素的个数大于等于k,则返回Sa中的第k大数。
    利用快排的partion思想T(n) = 2T(n/2) + O(1) 时间复杂度为O(n)
    该方法只有当我们可以修改输入的数组时可用,位于数组左边的k个数字就是最小的k个数字(但这k个数字不一定是排序的),位于第k个数右边的数字都比第k个数字大。
posted @ 2018-10-15 11:58  木易修  阅读(246)  评论(0编辑  收藏  举报