`
wangleide414
  • 浏览: 591976 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

查找第K小的元素的O(N)算法

 
阅读更多

话说这个问题,比较挫的解决方案有

1.先排序,然后找到第K小的,复杂度是O(nlogn)

2.选择排序来搞,选择排序是O(kn),

3.堆排序是O(nlogk)

4.比较好的解决方案是利用类似快速排序的划分思想来找到第K小,复杂度为O(n),但是最坏情况可能达到O(n^2)

5.还有种方法可以使得最坏情况也是O(n)。


我们先来看用快速排序的思想来搞的方案。快速排序是找到一个数,然后把所有数分为小于等于那个数的一堆,和大于那个数的一堆,然后两段分别递归来排序,而我们查找算法里,由于知道第K小的元素会在哪一堆,这样只需要递归其中一对即可。

 

  1. import random

  2.  

  3. def partition(arr, left, right, pivot):

  4.     v = arr[pivot]

  5.     arr[pivot], arr[right-1] = arr[right-1], arr[pivot]

  6.     index = left

  7.     for i in xrange(left, right):

  8.         if arr[i] <= v:

  9.             arr[i], arr[index] = arr[index], arr[i]

  10.             index += 1

  11.     return index-1

  12.  

  13. def select(arr, left, right, k):

  14.     while right - left > 1:

  15.         index = partition(arr, left, right, random.randint(left, right-1))

  16.         dist = index - left + 1

  17.         if dist == k:

  18.             return arr[index]

  19.         if dist < k:

  20.             k -= dist

  21.             left = index + 1

  22.         else:

  23.             right = index

  24.     return arr[left]

 

之后arr是要查找的数组,调用select即可找到第K小元素,如果pivot元素选的不好那么这个算法最坏的情况是O(n^2)。

现在讨论最坏情况下也是O(n)的方案,把所有的数分为5个一堆,那么总共会有n/5堆,对于每堆我们可以很快的找到中位数(因为只有5个所以很容易嘛),之后调用当前算法找到这n/5个中位数的中位数,用这个数来做pivot,所以这个算法被叫做Median of Medians algorithm。

把中位数的中位数作为pivot的话,那么原数组中便会有3/5*1/2个也就是3/10个小于等于这个pivot的,同理会有3/10大于这个pivot的,所以最坏情况下,数组被分为30%,70%或者70%,30%的两部分。

T(n)<=T(n/5)+T(7/10*n)+O(n)<=c*n*(1+9/10+(9/10)^2....) 
所以T(n)=O(n)

也就是最坏情况下是O(n)。

 

  1. import heapq

  2.  

  3. def partition(arr, left, right, pivot):

  4.     v = arr[pivot]

  5.     arr[pivot], arr[right-1] = arr[right-1], arr[pivot]

  6.     index = left

  7.     for i in xrange(left, right):

  8.         if arr[i] <= v:

  9.             arr[i], arr[index] = arr[index], arr[i]

  10.             index += 1

  11.     return index-1

  12.  

  13. def select_heap(arr, left, right, k):

  14.     tmp = arr[left:right]

  15.     heapq.heapify(tmp)

  16.     [heapq.heappop(tmp) for i in xrange(k-1)]

  17.     return heapq.heappop(tmp)

  18.  

  19. def median(arr, left, right):

  20.     num = (right - left - 1) / 5

  21.     for i in xrange(num+1):

  22.         sub_left = left + i*5

  23.         sub_right = sub_left + 5

  24.         if sub_right > right:

  25.             sub_right = right

  26.         m_index = select_heap(arr, sub_left, sub_right, (sub_right-sub_left)/2)

  27.         arr[left+i], arr[m_index] = arr[m_index], arr[left+i]

  28.     return select(arr, left, left+num+1, (num+1)/2)

  29.  

  30. def select(arr, left, right, k):

  31.     while right - left > 1:

  32.         pivot = median(arr, left, right)

  33.         index = partition(arr, left, right, pivot)

  34.         dist = index - left + 1

  35.         if dist == k:

  36.             return arr[index]

  37.         if dist < k:

  38.             k -= dist

  39.             left = index + 1

  40.         else:

  41.             right = index

  42.     return arr[left]

 

同理,如果快速排序每次选pivot时用Median of Medians algorithm也可以把最坏情况降低为O(nlogn)的。

分享到:
评论

相关推荐

    排序(下):如何用快排思想在O(n)内查找第K大元素?.pdf

    排序(下):如何用快排思想在O(n)内查找第K大元素?

    C++实现的O(n)复杂度内查找第K大数算法示例

    主要介绍了C++实现的O(n)复杂度内查找第K大数算法,结合实例形式分析了算法的原理以及具体实现方法,需要的朋友可以参考下

    Python要求O(n)复杂度求无序列表中第K的大元素实例

    题目就是要求O(n)复杂度求无序列表中第K的大元素 如果没有复杂度的限制很简单。。。加了O(n)复杂度确实有点蒙 虽然当时面试官说思路对了,但是还是没搞出来,最后面试官提示用快排的思想 主要还是设立一个flag,列表...

    宇空和米文的算法世界.pptx

    总共有n个元素,渐渐跟下去就是n,n/2,n/4,....n/2^k(接下来操作元素的剩余个数),其中k就是循环的次数由于你n/2^k取整后&gt;=1即令n/2^k=1可得k=log2n,(是以2为底,n的对数)所以时间复杂度可以表示O(h)=O(log2n) ...

    数据结构实验报告-查找算法.doc

    第八次实验报告 "学生姓名 " " "学生班级 " " "学生学号 " " "指导老师 " " 实验内容 1) 有序表的二分查找 建立有序表,然后进行二分查找 2) 二叉排序树的查找 建立二叉排序树,然后查找 需求分析 二分查找的基本...

    我用Python写的一些算法

    使用循环实现的算法o(n) ##数论算法 欧几里得算法求解最大公约数 ##字符串匹配算法 朴素算法 Rabin-Karp算法 KMP算法 #数据结构 ##树 二叉树 使用左孩子右兄弟实现的多叉树 二叉搜索树 红黑树 动态顺序统计树 ...

    常用算法代码

    | 取第 K 个元素 25 | 归并排序求逆序数 25 | 逆序数推排列数 25 | 二分查找 25 | 二分查找(大于等于 V 的第一个值) 25 | 所有数位相加 25 Number 数论 26 1 |递推求欧拉函数 PHI(I) 26 |单独求欧拉...

    C语言数据结构 广工 作业系统 09.查找

    实现下列函数: int Search(SSTable s, KeyType k); 9.26② 试将折半查找算法改写成递归算法。 9.31④ 试写一个判别给定二叉树是否为二叉...间复杂度为O(log2n+m),其中n为排序树中所含结点数, m为输出的关键字个数。

    数据结构和算法必知必会的50个代码实现

    * 实现归并排序、快速排序、插入排序、冒泡排序、选择排序* 编程实现O(n)时间复杂度内找到一组数据的第K大元素 ## 二分查找 * 实现一个有序数组的二分查找算法* 实现模糊二分查找算法(比如大于等于给定值的第一个...

    数据结构第九章 查找作业及答案(100分).docx

    1.在有序表A[1..18]中,采用二分查找算法查找元素值等于A[7]的元素,所比较过的元素的下标依次为 。 2.利用逐点插入法建立序列(61,75,44,99,77,30,36,45)对应的二叉排序树以后,查找元素36要进行 次元素间...

    深入第K大数问题以及算法概要的详解

    解法1: 我们可以对这个乱序数组按照从大到小先行排序,然后取出前k大,总的时间复杂度为O(n*logn + k)。 解法2: 利用选择排序或交互排序,K次选择后即可得到第k大的数。总的时间复杂度为O(n*k) 解法3: 利用快速...

    计算机二级公共基础知识

    例如,在一维数组[21,46,24,99,57,77,86]中,查找数据元素99,首先从第1个元素21开始进行比较,比较结果与要查找的数据不相等,接着与第2个元素46进行比较,以此类推,当进行到与第4个元素比较时,它们相等,...

    50个必会的数据结构及算法实现源码

    问题:编程实现O(n)时间复杂度内找到一组数据的第K大元素 二分查找、散列表、字符串处理、二叉树、堆、图、回溯、分治、动态回归等。 资源中包括常用语言:c、java、python、go等实现源码,方便参考学习。

    DSA:解决一些基本数据结构和算法问题

    kthmaxmin.cpp-在给定数组中打印第K个最大或最小数字的程序-O(nlogn) zeros.cpp-一个对0s,1s和2s数组进行排序的程序-O(n) negative.cpp-以恒定的额外空间将所有负数移动到开始并以正数结束的程序-O(n) ...

    《数据结构(Java版)(第2版)》习题解答

    Java程序设计基础\ 线性表 栈和队列 串 数组和广义表 树和二叉树 图 查找 排序

    lrucacheleetcode-algorithm-questions:Javascript中Leetcode算法问题的答案

    n) 二叉树中序遍历 BST 中第 K 个最小的元素 验证二叉树的预序序列化 验证二叉树的预序序列化 排序矩阵中的第 K 个最小元素 评估部门 编码和解码 TinyURL 插入删除 GetRandom O(1) - 允许重复 插入删除 GetRandom O...

    《数据结构 1800题》

    (2)在相同的规模 n下,复杂度O(n)的算法在时间上总是优于复杂度 O(2 n)的算法 (3)所谓时间复杂度是指最坏情况下,估算算法执行时间的一个上界 (4)同一个算法,实现语言的级别越高,执行效率就越低 A.(1) B...

    leetcode中国-Data_Structures-Algorithms:待补充!!

    leetcode中国数据结构和算法 数组 问题: 完成[是或否] 反转数组 查找数组中的最大和最小元素 ...k,找出出现次数超过“n/k”次的所有元素。 最多两次买卖股票的最大利润 判断一个数组是否是另一个数组的子集 找

    春节7天练丨Day3:排序和二分查找1

    1. 时间复杂度 2. 是否为原地排序 3. 算法的稳定性 1. O(n)时间内找到第K大的元素:

Global site tag (gtag.js) - Google Analytics