zoukankan      html  css  js  c++  java
  • 剑指 Offer 40. 最小的k个数(快排思想/大根堆)

    • 题目描述
    输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
    
     
    
    示例 1:
    
    输入:arr = [3,2,1], k = 2
    输出:[1,2] 或者 [2,1]
    示例 2:
    
    输入:arr = [0,1,2,1], k = 1
    输出:[0]
     
    
    限制:
    
    0 <= k <= arr.length <= 10000
    0 <= arr[i] <= 10000
    • 解法一:快排

    这里的快排,是指用快排思想,其实并不需要真正的排序。还记得快排的中值吗,当找到中值后,中值左边的数都比右边的数小,中值右边的数都比左边的数大,那么,我们只需要判断需要找的k个数的k-1的索引与中值的索引的关系:

    1.中值索引等于k-1,那么此时中值左边刚好就是要找的k个数;

    2.中值索引>k-1,那么说明这k个数在中值的左半部分,我们只需要对中值左边部分继续分界,直到中值索引等于k-1

    3.中值索引<k-1,那么说明这个k个数在中值右半部分,我们只需要对中值右边的部分继续分界,直到中值索引等于k-1

    那么这里有两种代码实现,一种是对结果排好序的,一种是没排好序的

    没排好序的:

    class Solution:
        def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
            start = 0
            end = len(arr) - 1
            point = self.quicksort(arr, start, end)
    
            while point != k-1:
                if point < k -1:
                    start = point + 1
                    point = self.quicksort(arr, start, end)
                if point > k-1:
                    end = point - 1
                    point = self.quicksort(arr, start, end)
            return arr[:k]
    
        def quicksort(self, alist, first, last):
            middlepoint = alist[first]
            leftmark = first + 1
            rightmark = last
            done = False
            while not done:
                while leftmark <= rightmark and alist[leftmark] <= middlepoint:
                    leftmark += 1
                while rightmark >= leftmark and alist[rightmark] >= middlepoint:
                    rightmark -= 1
                if leftmark > rightmark:
                    done = True
                else:
                    alist[leftmark], alist[rightmark] = alist[rightmark], alist[leftmark]
            alist[first], alist[rightmark] = alist[rightmark], alist[first]
            return rightmark  # 中值的索引

    排好序的:

    class Solution(object):
        def getLeastNumbers(self, arr, k):
            """
            :type arr: List[int]
            :type k: int
            :rtype: List[int]
            """
            # 方法一:partition方法(基于快速排序)
            if k > len(arr) or k <= 0:
                return [] 
            start = 0
            end = len(arr) - 1
            index = self.quickSort(arr, start, end)
            while index != k-1:
                # print(index)
                if index > k-1:
                    end = index - 1
                    index = self.quickSort(arr, start, end)
                if index < k-1:
                    start = index + 1
                    index = self.quickSort(arr, start, end)
            return arr[:k]
    
        def quickSort(self, arr, start, end):
            low = start
            high = end
            temp = arr[start]
            while low < high:
                while low < high and arr[high] >= temp:
                    high -= 1
                arr[low] = arr[high]
                while low <high and arr[low] < temp:
                    low += 1
                arr[high] = arr[low]
            arr[low] = temp
            return low

    时间复杂度O(N),最坏情况为O(N^2)

    空间复杂度O(log n)

    递归调用期望深度为O(log n)

    • 大根堆

    大根堆的是一个队列形式实现,堆顶保存的是始终是最大的数,那么我们可以这样,先将数组前k个数放到大根堆里面去,再从k+1依次遍历,假如新的数比堆顶下,那么把堆顶弹出,把这个数存到大根堆里面去,那么一趟遍历下来,大根堆始终维护着最小的k个数。

    但是在Python里面没有大根堆,python的实现是小根堆,可以调用heapq。那么呢,需要把这个数组取反存在小根堆去,小根堆堆顶始终维护者最小的数,那么它的相反数其实在真是的数中就是最大的数,那么同理,遍历k+1,假如新的数比小根堆顶元素的相反数小的话,那么就存在小根堆里面去,然后把小根堆的堆顶pop出去。记得return的时候也需要取相反数。

    from heapq import *
    class Solution:
        def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
            '''
            python小根堆
            '''
            if k == 0:
                return []
            hp = [-x for x in arr[:k]]
            heapq.heapify(hp)
            for i in range(k, len(arr)):
                if -hp[0] > arr[i]:
                    heapq.heappop(hp)
                    heapq.heappush(hp, -arr[i])
            return [-x for x in hp]

    时间复杂度O(n log k),其中n是数组长度

    空间复杂度O(k),小根堆里面最多有k个数

     
  • 相关阅读:
    SSM框架整合步骤
    Spring-data-jpa
    allure定制报告
    pytest常用选项
    staticmethod&classmethod&property
    __slot__
    python的参数传递
    闭包和装饰器
    内置高阶函数
    str
  • 原文地址:https://www.cnblogs.com/yeshengCqupt/p/13533614.html
Copyright © 2011-2022 走看看