文章目录

  • 引言
  • 1.求最小的k个数
    • 剑指 Offer 40. 最小的k个数
  • 2.求最大的k个数

引言

  这是一类面试中特别容易被问到的题目,这里采用两种方法二叉堆与快速排序,直接排序与冒泡k次这里就不多赘述了,虽然写法简单,但是时间复杂度过高!!!

1.求最小的k个数

剑指 Offer 40. 最小的k个数

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

思路一:二叉堆

思路:建立一个大顶堆,维持堆的大小为k,如果新入队后,堆的大小大于k,则与新入队元素与堆顶比较,将较大的数移除,这样就可以保证堆中的元素是全体元素中最小的k个,此时,堆顶元素为第k小的值。堆是最小的k个数,堆顶又是最大的,因此堆顶就是第k小的

class Solution:def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:# 思路是:利用python中的最小堆模拟最大堆,每一次与堆顶元素比较,如果比堆顶元素大,则弹出堆顶元素并添加当前元素# 数组if k == 0:return []heap = [-i for i in arr[:k]]# 构造二叉堆heapq.heapify(heap)# 对数组的剩余元素与堆顶元素进行比较for i in range(k,len(arr)):# 如果堆顶元素相反数比当前元素大if -heap[0] > arr[i]:heapq.heappop(heap)heapq.heappush(heap,-arr[i])ans = list(map(lambda x : -x,heap))return ans

时间复杂度:O(nlogk),其中 n 是数组 arr 的长度。由于大根堆实时维护前 k 小值,所以插入删除都是 O(logk) 的时间复杂度,最坏情况下数组里 n 个数都会插入,所以一共需要 O(nlogk) 的时间复杂度。
空间复杂度:O(k),因为大根堆里最多 k 个数。

思路二:快速排序

快速选择算法:
这个问题可以转化为求第k小的数,此时,前k个位置正是最小的k个数
1. 先按基准位置进行分区,分区左侧小于基准位置,分区右侧大于基准位置,返回基准位置的索引
2.索引与k-1进行比较,对剩余位置进行分区,直至索引等于k-1

class Solution:def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:# 快速选择算法:# 这个问题可以转化为求第k小的数,此时,前k个位置正是最小的k个数# 1. 先按基准位置进行分区,分区左侧小于基准位置,分区右侧大于基准位置,返回基准位置的索引# 2.索引与k-1进行比较,对剩余位置进行分区,直至索引等于k-1if k == 0:return []def partation(arr,begin,end):# 基准位置从左侧开始选取mid_value = arr[begin]while begin < end:# 从右侧寻找比基准值小的数,从左侧寻找比基准值大的数while begin < end and arr[end] >= mid_value:end -= 1arr[begin] = arr[end]while begin < end and arr[begin] <= mid_value:begin += 1arr[end] = arr[begin]# 循环结束时,begin=endarr[begin] = mid_value# 返回基准值索引return beginn = len(arr)begin = 0end = n - 1index = partation(arr,begin,end)# 求第k小元素while index != k-1:# 说明要对index左侧继续分区if index > k-1:end = index-1index = partation(arr,begin,end)else:begin = index + 1index = partation(arr,begin,end)# 循环结束时index = k-1return arr[:k]

时间复杂度:期望为 O(n)O(n)O(n)
最坏情况下的时间复杂度为 O(n2)O(n^2)O(n2)。情况最差时,每次的划分点都是最大值或最小值,一共需要划分 n−1 次,而一次划分需要线性的时间复杂度,所以最坏情况下时间复杂度为 O(n2)O(n^2)O(n2)。

2.求最大的k个数

思路一:二叉堆

使用最小堆,维持堆的大小为k,如果新入队后,堆的大小大于k,则与新入队元素与堆顶比较,将较小的数移除,这样就可以保证堆中的元素是全体元素中最大的k个

class Solution:def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:# 思路是:利用python中的最小堆模拟最大堆,每一次与堆顶元素比较,如果比堆顶元素大,则弹出堆顶元素并添加当前元素# 数组if k == 0:return []heap = [i for i in arr[:k]]# 构造二叉堆heapq.heapify(heap)# 对数组的剩余元素与堆顶元素进行比较for i in range(k,len(arr)):# 如果堆顶元素相反数比当前元素大if heap[0] < arr[i]:heapq.heappop(heap)heapq.heappush(heap,arr[i])return heap

时间复杂度:O(nlogk),其中 n 是数组 arr 的长度。由于小根堆实时维护前 k 大值,所以插入删除都是 O(logk) 的时间复杂度,最坏情况下数组里 n 个数都会插入,所以一共需要 O(nlogk) 的时间复杂度。
空间复杂度:O(k),因为大根堆里最多 k 个数。
思路二:快速排序

快速选择算法:
这个问题可以转化为求第k大的数,此时,后k个位置正是最大的k个数
1. 先按基准位置进行分区,分区左侧小于基准位置,分区右侧大于基准位置,返回基准位置的索引
2.索引与n-k进行比较,对剩余位置进行分区,直至索引等于n-k

#!usr/bin/env python
# -*- coding:utf-8 -*-
"""
@author: admin
@file: 快速选择.py
@time: 2021/05/23
@desc:
"""def getLeastNumbers(arr, k):def partation(arr, begin, end):# 基准位置从左侧开始选取mid_value = arr[begin]while begin < end:# 从右侧寻找比基准值小的数,从左侧寻找比基准值大的数while begin < end and arr[end] >= mid_value:end -= 1arr[begin] = arr[end]while begin < end and arr[begin] <= mid_value:begin += 1arr[end] = arr[begin]# 循环结束时,begin=endarr[begin] = mid_value# 返回基准值索引return beginn = len(arr)begin = 0end = n - 1index = partation(arr, begin, end)# 求第k小元素while index != n-k:# 说明要对index左侧继续分区if index > n-k:end = index - 1index = partation(arr, begin, end)else:begin = index + 1index = partation(arr, begin, end)# 循环结束时index = n-kreturn arr[n-k:]if __name__ == '__main__':# arr = [0,0,0,2,0,5]arr = [54, 26, 93, 17, 77, 31, 44, 55, 20]k = 5result = getLeastNumbers(arr, k)print(result)

如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论或者私信!


leetcode—26.求前k大值与前k小值相关推荐

  1. 定义一个函数模板,要求返回两个值中的较小值。

    #include<iostream> using namespace std; template<typename T>//定义函数模板,T为类型参数; T cmin(T a, ...

  2. 堆排序 海量数据求前N大的值

    最(大)小堆的性质: (1)是一颗完全二叉树,遵循完全二叉树的所有性质. (2)父节点的键值(大于)小于等于子节点的键值 堆的存储 一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2. ...

  3. 算法12--topK求一个数组中第k大的数

    求一个数组中第k大的值 解法一: 建立一个k个元素的最大堆,首先将数组中前k个元素放入堆中,此时堆顶元素为第k大的元素,后面继续遍历数组,比较堆顶元素与数组中元素值,当数组中元素小于堆顶元素时,将堆顶 ...

  4. 无序数组求第K大/第K小的数

    方法一:quicksort 根据快排思想,从后往前找比基准数小的,交换位置. 从前往后找比基准数大的,交换位置. 最后安放基准数. 保证 l到p 是大数,若 p-l+1==k 那么p就是第K大 若 p ...

  5. 单峰数组求第k大算法

    单峰数组实际上可以看成两个有序的数组,这个问题就转变成了两个有序数组求第k大. 容易想到的算法是对这两个数组进行归并,生成一个新的有序数组,求出第k大之后就可以立刻停止,复杂度是O(k)的. 但是还有 ...

  6. 算法题 求第K大的数

    题目描述:在乱序数组中求第K大的数 思路:立刻想到的是当然先排序然后取数.但是提问者明显不是想这么解.上网查了下原来是快排思路. 利用快排的思想,从数组arr中随机找出一个元素X,把数组分成两部分ar ...

  7. 在一个无序的int数组上构建一个最小堆的时间复杂度_漫画:寻找无序数组的第k大元素(修订版)...

    ----- 第二天 ----- 题目是什么意思呢?比如给定的无序数组如下: 如果 k=6,也就是要寻找第6大的元素,这个元素是哪一个呢? 显然,数组中第一大的元素是24,第二大的元素是20,第三大的元 ...

  8. 数组中的元素赋值给元素_漫画:寻找无序数组的第k大元素

    本期封面作者:泰勒太乐 -----  第二天  ----- 题目是什么意思呢?比如给定的无序数组如下: 如果 k=6,也就是要寻找第6大的元素,这个元素是哪一个呢? 显然,数组中第一大的元素是24,第 ...

  9. 如何寻找无序数组中的第K大元素?

    如何寻找无序数组中的第K大元素? 有这样一个算法题:有一个无序数组,要求找出数组中的第K大元素.比如给定的无序数组如下所示: 如果k=6,也就是要寻找第6大的元素,很显然,数组中第一大元素是24,第二 ...

  10. 从当前元素继续寻找_云漫圈 | 寻找无序数组的第k大元素

    戳蓝字"CSDN云计算"关注我们哦! 作者:小灰 来源:程序员小灰 本期封面作者:泰勒太乐 -----  第二天  ----- 题目是什么意思呢?比如给定的无序数组如下: 如果 k ...

最新文章

  1. 厉害!苏炳添即将在暨南大学成立短跑实验室
  2. 动态主机配置协议服务器不能提供,计算机网络基础课程—动态主机配置协议(Dhcp)...
  3. ajax实现简单的点击左侧菜单,右侧加载不同网页
  4. 异常通知(After Throwing Advice)
  5. 使用 Cake 推送 NuGet 包到 AzureDevops 的 Artifacts 上
  6. gin+vue的前后端分离开源项目
  7. python的简单程序代码_小白学编程?从一个简单的程序开始学习Python编程
  8. WPF的ListBox的数据绑定,但需要添加控件在里面的时候
  9. java 链表反转_面试必备 | 不可不会的反转链表
  10. java语言实现二维数组构造二叉树_剑指offer打卡5:二叉树的子结构
  11. Quartus II破解出现的问题
  12. 精品思维导图模板合集,锻炼你的逻辑思维,提升能力空间
  13. python3 函数类型限制登录可解封_如何解决python反爬虫限制访问?
  14. U3d引擎与资源管理
  15. 4.list和tuple的使用
  16. 基因组选择中的参考群更新策略
  17. 北京大学|北京大学介绍|北京大学简介
  18. 【参赛作品61】openGauss/MogDB大对象LargeObject存取测试
  19. keepalived工作原理和配置说明
  20. 2022.12.8 半导体器件物理

热门文章

  1. msyql 授权ip
  2. Windows8 Metro应用开发之C#(3)- 数据控件ListView、GridView、FlipView
  3. 使用.NET框架自带的Json序列化类
  4. HTML 5 input placeholder 属性 实现搜索框提示文字点击输入后消失
  5. HDOJ 1420 Prepared for New Acmer(DP)
  6. HDUOJ----4504 威威猫系列故事——篮球梦
  7. java基础-- 集合框架入门 及 List集合
  8. STL之list介绍
  9. 转 sql server性能分析--执行sql次数和逻辑次数
  10. varchar,char,varchar2,mybatis查询无返回