40 最小的k个数(python)

这篇博客探讨了在给定整数数组中找出最小k个数的几种方法,包括整体排序、k轮冒泡排序、基于快速排序的Partition思想和堆排序。通过详细解释每种方法的实现原理和时间复杂度,展示了如何在不同情况下优化查找效率。

题目

输入n个整数,找出其中最小的k个数。例如输入4、5、1、6、2、7、3、8 这8个数字,则最小的4个数字是1、2、3、4。

方法一:(最简单的思路)整体排序后取前k个数

class Solution:
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        return sorted(arr)[:k]

复杂度:O(nlogn)

方法二:k轮冒泡排序

class Solution:
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        if k <= 0 or k > len(arr):
            return []    
        for i in range(k):
            for j in range(i+1, len(arr)):
                if arr[i] > arr[j]:
                    arr[i], arr[j] = arr[j], arr[i]
        return arr[:k]

复杂度:O(kn)
如果k很大,超出时间限制,

快排中的Partition思想

①随机选一数为key,在partition函数中完成一轮比较的结果是,比key大的数都在其右边,比key小的数放在其左边。返回 key的index。
②判断index与k的大小:
如果 index > k,说明前k小的数在key左边,故需把寻找范围缩小,在key左侧找。
如果 index < k,说明上轮partition之后,前index个数找的太少了,我们需要再往数组的后面找。

class Solution:
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        if k <= 0 or k > len(arr):
            return []
        start = 0 
        end = len(arr) - 1
        mid  = self.partion(arr, start, end)
        while k - 1 != mid:
            if k - 1 < mid:
                end = mid - 1
                mid  = self.partion(arr, start, end)
            elif k - 1 > mid:
                start = mid + 1
                mid  = self.partion(arr, start, end)
        return arr[:k]

    def partion(self, nums, low, high):
        key = nums[low]
        while low < high:
            while low < high and nums[high] >= key:
                high -= 1
            nums[low] = nums[high]
            while low < high and nums[low] <= key:
                low += 1
            nums[high] = nums[low]
        nums[low] = key
        return low
# 注意partion中判断大小一定要有等号,否则会陷入死循环
# 注意判断k的极值          

时间复杂度: 因为我们是要找下标为k的元素,第一次切分的时候需要遍历整个数组 (0 ~ n) 找到了下标是 j 的元素,假如 k 比 j 小的话,那么我们下次切分只要遍历数组 (0~k-1)的元素就行啦,反之如果 k 比 j 大的话,那下次切分只要遍历数组 (k+1~n) 的元素就行啦,总之可以看作每次调用 partition 遍历的元素数目都是上一次遍历的 1/2,因此时间复杂度是 N + N/2 + N/4 + … + N/N = 2N, 因此时间复杂度是 O(N)

堆排序

heap:寻找找到一堆数中的最大值或者最小值的数据结构

一个很常见的例子,假设我们要选5个最矮的同学参加比赛,候选人选好之后又跑来一个新同学参加评选。这个时候新同学只需要PK候选人中最高的,如果他比最高的还高,就被淘汰,如果比最高的矮,他就可以替代这个最高的。按照这个思想,无论再来多少新同学都可以很快速的选择。

以这个思想为基础,为了最快的找到候选人中最高的,以身高为基准建立大顶堆,每次新人与堆顶PK,PK结束之后维护候选人重新为大顶堆。

这种思想将时间复杂度降到以k为基数,每次调整堆的时间复杂度都是,那么整体时间复杂度为。

现成
# -*- coding:utf-8 -*-
import heapq
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        if len(tinput) < k:
            return []
        return heapq.nsmallest(k, tinput)
手写堆
https://blog.csdn.net/qq_20141867/article/details/81152894
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值