Top K 问题的最优解 - 快速选择算法(图解详细教程)
文章目录
- Leetcode 215. Kth Largest Element in an Array
- 1.1:快速选择算法流程
- 1.2:注意事项
- 1.3:python实现
- Leetcode 973. K Closest Points to Origin
- 1.1 题意
- 1.2 思路
- 1.3 python实现
- 3. 牛客:最小的K个数
- 3.1 题意:
- 3.2 分析
- 3.3 python实现
- 最后:heapq模块实现top N---nlargest()和nsmallest()函数
Leetcode 215. Kth Largest Element in an Array
题意:给定一个无序的数组,寻找第K大的元素。
1.1:快速选择算法流程
输入:
nums = [3,2,1,5,6,4]
k=2
- step 1: 随机选择一个 pivot,通过一系列计算,查看是否是我们需要找到的 Top k 对应的 pivot
- step 2: 把 pivot 移动到最右的位置,以最右为标杆,从头开始对剩余部分进行选择查找
- step 3: 定义两个指针,初始化为0,查看 j 所在的指针是否小于等于 pivot,4 大于 3,所以我们把 j 指针右移一位
- step 4: 查看 j 所在的指针是否小于等于 pivot,2 小于等于 3,我们替换 i 指针和 j 指针所在的位置,同时把 i 和 j 指针都右移一位。
- step 5: 查看 j 所在的指针是否小于等于 pivot,1 小于等于 3,我们替换 i 指针和 j 指针所在的位置,同时把 i 和 j 指针都右移一位。
- step 6: 重复上述步骤,直到 j 指针移动到最右边
- step 7: 把pivot放到中间来,把数组划分为左右两个部分
- step 8: 此时 pivot 3 左边的值都小于 3,右边的值都大于 3,pivot 3 对应的是 Top 4 而不是 我们需要找的 Top 2,但我们可以知道,Top 2 一定在 pivot 3 右边的位置。
- step 9: 把右半部分按照重复执行上述步骤,最终找到 Top 2 的 pivot,对应的值为 5
1.2:注意事项
pivot 的选择很重要,如果对于一个已排序的数组,我们每次都选择最大/最小的值为 pivot,那么时间复杂度为 O(N^2) 。每次通过 random 选择 pivot 可以尽量避免最坏情况发生。
快速选择算法的平均时间复杂度是 O(N),但最坏情况下的时间复杂度是 O(N^2) ,因为我们已经随机选择 pivot,所以能够最大程度上的减少最坏情况发生
1.3:python实现
def findKthLargest(self, nums, k):def quickSelect(nums, lo, hi, k): # 从小到大排序pivot = random.randint(lo, hi) # 0-len(nums)-1中随机取一个下标,避免最坏的情况nums[hi], nums[pivot] = nums[pivot], nums[hi] # 最右边存这个支点i = j = lowhile j < hi:if nums[j] <= nums[hi]: # 找到一个比支点还小的数nums[i], nums[j] = nums[j], nums[i] # i, j相互交换i += 1j += 1 # 每一次j都要前进一步nums[i], nums[j] = nums[j], nums[i] # 把pivot放到中间来if hi > k + i - 1: # Topk在右边return quickSelect(nums, i + 1, hi, k) elif hi < k + i -1: # Topk在左边return quickSelect(nums, lo, i - 1, k - (hi - i + 1))else:return nums[i]return quickSelect(nums, 0, len(nums)-1, k)
Leetcode 973. K Closest Points to Origin
1.1 题意
给定一个二维数组,数组中每一行代表一个点,求距离原点(0,0)最近的K个点
1.2 思路
还是按照以上的快速选择排序算法,稍微做一点点修改:
- 上一题的数组是从小往大排序,最后从右边开始数第K大的元素。
- 这一题是从大往小排序,最后从右边开始数K个小的元素,返回一个数组。
1.3 python实现
def kClosest(self, points, K):# 从小到大,找的是从右边数的第k大的元素def quickSort(points, lo, hi, k):pivot = random.randint(lo,hi) #在闭区间里面选择points[hi], points[pivot] = points[pivot], points[hi]i = j = lowhile j < hi: # 从左到右开始遍历if dis(points[j]) > dis(points[hi]): # 修改1:从大往小排序points[i], points[j] = points[j], points[i] # 交换点i,j,把小数移到左边去i += 1j += 1points[i], points[j] = points[j], points[i] # 把pivot放在中间来# 以下是根据pivot的位置来进行划分if hi > k + i -1: # i太小了,Topk在右边return quickSort(points, i+1, hi, k)elif hi < k + i - 1: # Topk在左边return quickSort(points, lo, i-1, k-(hi-i+1))else:return points[i:][:] # 修改2:返回最后的k个最近的点def dis(dot): # 求得距离return dot[0]**2 + dot[1]**2return quickSort(points, 0, len(points)-1, K) # 要的是从左往右的点
3. 牛客:最小的K个数
链接:最小的k个数
3.1 题意:
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
3.2 分析
这道题和上一道题"距离原点最近的k个节点"非常类似,因此也可以使用快速选择算法来做,并且时间复杂度很低,O(N)来做了
3.3 python实现
import random
class Solution:def GetLeastNumbers_Solution(self, tinput, k):# write code hereif k <=0 or k > len(tinput) or not tinput: return []def quickSelect(nums, lo, hi, k): # 从小到大排序pivot = random.randint(lo, hi) # 0-len(nums)-1中随机取一个下标,避免最坏的情况nums[hi], nums[pivot] = nums[pivot], nums[hi] # 最右边存这个支点i = j = lowhile j < hi:if nums[j] > nums[hi]: # 找到一个比支点还大的数nums[i], nums[j] = nums[j], nums[i] # i, j相互交换,把大数放后面i += 1j += 1 # 每一次j都要前进一步nums[i], nums[j] = nums[j], nums[i] # 把pivot放到中间来if hi > k + i - 1: # Topk在右边return quickSelect(nums, i + 1, hi, k) elif hi < k + i -1: # Topk在左边return quickSelect(nums, lo, i - 1, k - (hi - i + 1))else:return nums[i:]res = quickSelect(tinput, 0, len(tinput)-1, k)res.sort() # 可能退化为O(N^2)啊!return res
最后:heapq模块实现top N—nlargest()和nsmallest()函数
通过以上快速选择算法选择的top N个元素后,原来的数组的顺序已经打乱了,使用heapq模块取出top N个元素后,不会修改原来的数组的顺序!
>>> import heapq
>>> nums=[1,8,2,23,7,-4,18,23,42,37,2]
>>> print(heapq.nlargest(3,nums)) # 从大到小排序
[42, 37, 23]
>>> print(heapq.nsmallest(3,nums)) #从小到大排序
[-4, 1, 2]
Top K 问题的最优解 - 快速选择算法(图解详细教程)相关推荐
- Top k问题(线性时间选择算法)
问题描述:给定n个整数,求其中第k小的数. 分析:显然,对所有的数据进行排序,即很容易找到第k小的数.但是排序的时间复杂度较高,很难达到线性时间,哈希排序可以实现,但是需要另外的辅助空间. 这里我提供 ...
- 快速幂算法 超详细教程
快速幂 求幂运算 快速幂引入 快速幂 二进制 快速幂 指数折半 快速幂的应用 求幂运算 求幂运算大家都不陌生,幂是指数运算的结果,当m是正整数时nᵐ的意义为m个n相乘,n的m次幂也就是n的m次方.用代 ...
- linux 6.8 安装教程,CentOS 6.8 7.2 安装图解详细教程
PS:文章转载,虽然基础,还是希望各位路过看官仔细看后实操一次,您才知道途中有那些坑! 感谢作者整理: 1.安装CentOS 6.8 用光盘成功引导系统,会出现下面的界面 这里选择第一项,安装或升级现 ...
- MySQL安装图解详细教程
1.安装MySQL 2.校验MySQL 注意:安装路径不要包含中文!!!最好使用英文或者拼音. 安装图解如下: 接下来有三个按钮: 第一个按钮表示典型安装(推荐的安装) 第二个按钮表示自定义安装(一般 ...
- 什么是计算机嵌套分类汇总,Excel中插入分类汇总的嵌套级别的方法图解详细教程...
在上文我们讲解了Excel 2010工作表中为一组数据插入一个分类汇总级别的方法,本文则讲解了Excel 2010工作表中插入分类汇总的嵌套级别的方法. Excel 2010工作表中可以在相应的外部组 ...
- pythonqt5安装路径配置_PyQt5 安装与环境配置方法图解详细教程
PyQt5 是用来创建Python GUI应用程序的第三方工具包,它不仅与Python有着良好的兼容性,还可以通过可视化拖拽的方式进行窗体的创建,提高开发人员的工作效率,因此深受开发人员的喜爱.作为一 ...
- GitHub修改昵称和用户名(图解详细教程)
1.登录GitHub.https://github.com/ 2.点击右上角头像>>Settings 3.点击进入Settings后显示的页面即为设置/修改昵称的页面 注意:Profile ...
- 找出无序数组中最小的k个数(top k问题)
2019独角兽企业重金招聘Python工程师标准>>> 给定一个无序的整型数组arr,找到其中最小的k个数 该题是互联网面试中十分高频的一道题,如果用普通的排序算法,排序之后自然可以 ...
- 快速选择算法-基于快排
目录 快速选择算法 例题 算法思路 代码实现 快速选择算法 快速选择,就是在一个无需的数组中查找第k个小的数.我们可以很快的想到可以先将数组排序在进行选择,但时间复杂度为O(nlogn)O(n\lo ...
最新文章
- mysql 复合索引 in,MySQL复合索引比主键索引还快,为什么?
- python和vb的代码可以通用吗-python和vb哪个简单
- C# 对象深拷贝、浅铐贝、直接拷贝(转)
- 不是世界不好,而是你见得太少
- linux使用设备文件的目录,Linux系统下的/dev目录
- 计算机视觉与图像处理面试题,深度学习图像处理算法工程师面试题
- python中的property_python中的property属性
- B站网站后台工程源码泄露 用户信息还安全吗?
- gb/t19011-2013 管理体系审核指南
- 电机正反转c语言注释,直流电机正反转C程序.doc
- Ubuntu一些名词解释
- camera 自动对焦手动对焦
- 数字化住宅小区对计算机网络有需求,浅谈智能小区宽带接入及其技术发展趋势...
- 小米忙着营销,麻烦带上技术!
- lmdb.Error: 路径 : ϵͳ�Ҳ���ָ����·����解决办法
- c语言编程的难点,c语言编程的难点
- 计算机用鼠标画图,在电脑上用鼠标画画用那个软件好
- 黑猫带你学UFS协议第1篇:全网最全UFS协议中文详讲,这份学习框架图,你值得拥有!!!(持续更新中...)
- JS UMD深入学习(二)—— node_module是commonjs标准,工程目录是ES6标准
- uboot源码分析(基于S5PV210)之启动第一阶段