求数组中第K的元素的一般方法就是使用快速排序的划分,
Partion(seq,start,end) = p, 如果p=k 则ok。如果p >k
则在start, p -1的区间里找第K大的数,Partion(seq,start,p-1)
否则partion(seq,p+1,end)
算法的平均时间复杂度为O(N),最坏情况为N^2,即每次划分把数组变为为(n-1) 和1的两断.
对此算法导论上给出了一个最坏情况下为O(N)的算法
该算法就是每次partion的时候找到一个好的划分,用中位数的中位数作为pivot。
把数组分为 N/5组,每组插入排序之后求得中位数,共 N/5 个中位数,对这N/5 中位数,使用同样过程再排序再求中位数(递归完成),最后求得N/5的中位数的中位数 作为最佳pivot,如下。
private static int getPerfectPivot (int[]seq,int start,int end){ if(start==end){ return seq[start]; } int groups = (end-start+1)%5==0?(end-start+1)/5:(end-start+1)/5+1; int[] group_median = new int[groups]; for(int i=0; i < groups;i++){ int from = start+i*5; int to = (from+5 < end)?(from+5):end; for(int k=from+1;k<to;k++){ if(seq[k] < seq[k+1]){ //sawp int temp = seq[k]; seq[k] = seq[k+1]; seq[k+1] =temp; } } group_median[i] = seq[(from+to)/2]; } return getPerfectPivot(group_median,0,groups-1); }
稍微修改Partion的过程,即可获得O(N)复杂度的算法
private static int partionByMedian(int start,int end, int[]seq){ int pivot = getPerfectPivot (seq,start,end); //这里不再使用最后一个元素,也不使用rand随机设定一个元素 int swap_index = start -1; for(int i = start;i<end;i++){ if(seq[i] <pivot){ swap_index++; int temp = seq[swap_index]; seq[swap_index] = seq[i]; seq[i] = temp; } if(seq[i]==pivot && seq[end]!=pivot){ int temp = seq[i]; seq[i] = seq[end]; seq[end] = temp; i--; } //这一段是找出最好的pivot在数组中的位置并放到末尾。 } swap_index++; seq[end] = seq[swap_index]; seq[swap_index] = pivot; return swap_index; }
整个算法的执行时间可证明为O(N)参考算法导论。
相关推荐
在编程和算法设计中,"求第K大元素"是一个常见的问题,特别是在数据处理和排序算法的场景下。这个问题的基本目标是从一个数组或集合中找出第K个最大的元素,其中K通常是一个正整数,且K小于等于数组的元素个数。这个...
从数组的第一个元素开始,跳过k-1个元素,比较第k个元素与前k-1个元素中的最大值。如果第k个元素比最大值小,更新最大值。接着,跳过k个元素,再比较第2k个元素,依此类推。直到遍历完整个数组,最后的最大值即为第k...
在计算机科学中,"求第k小元素"是算法设计中的一个重要问题,它涉及到排序和查找的技巧。这个问题的目标是从一个未排序或者部分排序的数组或集合中找到第k个最小的元素,其中k通常是一个正整数。这个问题在数据分析...
本问题涉及的是一个特定的数组操作,即“换位”操作,它要求将数组的前k个元素与剩余的n-k个元素进行交换,而这个过程需要在最坏情况下达到线性时间复杂度O(n)。这里我们主要关注如何用Java来实现这个算法。 首先,...
在编程和算法设计中,"数组中求第K大数"是一个常见的问题,它涉及到高效地从一组数据中找出第K...然而,需要注意的是,最坏情况下,当输入数组已经部分有序时,时间复杂度可能退化为O(n^2),但这在实际情况中较为罕见。
接下来,我们将探索如何使用快速排序的思想,在O(n)的时间复杂度内找到数组中的第K大元素。 **基本思路**: 1. **选择基准**:从数组中随机选择一个元素作为基准。 2. **分区操作**:将数组按照选定的基准进行分区...
由于每次划分都能减少一半的搜索范围,平均时间复杂度为O(n),最坏情况下为O(n^2)。 2. **最小堆**:可以使用一个大小为k的最小堆来解决这个问题。遍历数组,每次遇到新的元素,如果堆的大小小于k,就将其插入堆中...
随机选择查找的平均时间复杂度为O(n),但最坏情况下的时间复杂度为O(n^2)。 3. **排序查找**: 最简单直接的方法是先对整个数组进行排序,然后直接返回第k个元素。在C++中,可以使用内置的`std::sort`函数对数组...
- 文件是关于“最坏时间为线性的第k大元素的测试数据”,这意味着我们要找到一个算法,其在最坏情况下,即数据集分布最为不利时,仍能以线性时间复杂度找到第k大的元素。一个典型的算法是快速选择算法(QuickSelect...
在最坏的情况下,时间复杂度可能退化到O(n^2),但通过选择良好的基准元素(如中位数的中位数),这种情况的概率非常低。 - **空间复杂度**:由于SELECT算法主要依赖于递归调用栈,其空间复杂度为O(log n),这是因为...
不过,需要注意的是,虽然平均时间复杂度是O(n),但在最坏情况下,例如数组已经按升序排列,该方法的时间复杂度会退化到接近O(n^2),因此实际应用时需要考虑数据分布情况。在实际编程中,还可以考虑使用优先队列(堆...
快速选择算法基于快速排序的思想,平均时间复杂度为O(n),最坏情况为O(n^2)。堆排序则可以通过构建最大堆,然后反复调整堆顶元素来找到第K小的元素,其时间复杂度为O(n log n)。在`第k小元素.cpp`文件中,你可以找到...
这篇文章将详细介绍如何在O(n)的时间复杂度内找到数组中的第K大数。 首先,理解这个问题的核心是利用快速排序的分治思想。快速排序通常用于对整个数组进行排序,但在这里我们并不需要完全排序,而是只需要找到第K大...
其最好情况(已排序数组)下达到O(n)的时间复杂度,但在最坏情况下的时间复杂度仍为O(n²)。 3. 选择排序:选择排序在每一轮中找到未排序部分的最小(或最大)元素,然后将其放到正确的位置。其时间复杂度始终为O(n...
- **冒泡排序**:通过不断交换相邻的逆序元素来逐渐排序,其最坏情况下的时间复杂度为O(n^2),但在最佳情况下(已排序数组)能达到O(n)。 - **快速排序**:由C.A.R. Hoare提出的,使用分治策略。选取一个基准值,...
- **缺点**:最坏情况下时间复杂度为O(n^2),但这种情况在寻找第k小元素时不太可能出现。 3. **中位数法**: - **概念**:中位数法是通过寻找数组的中位数来划分数据,使得划分后的两部分大小大致相等,进一步...
平均时间复杂度为O(n log n),最坏情况下为O(n^2)。 5. 归并排序(Merge Sort) 归并排序也是分治策略的一种,将数组分成两半分别排序,再合并成有序序列。无论数据情况如何,其时间复杂度都为O(n log n),但需要...
这个问题要求在一组无序的元素中找到第k小(或第k大)的元素,而不必对整个序列进行完全排序。在本案例中,我们关注的是如何使用分治策略来解决这个问题,并通过Python 3.7实现。 分治法是一种重要的算法设计策略,...
这个问题的目标是在一个无序或有序的数组中找出第K小(或第K大)的元素。这个问题有多种解决方案,包括使用排序算法、堆排序、二分查找等方法。在这个场景中,我们讨论的是一种特定的算法实现。 首先,我们需要理解...
尽管直观但效率低下,通常采用字符串排序算法对所有后缀进行排序,其最坏情况下的时间复杂度为O(n^2)。 **2. 倍增算法** - **k-前缀定义**:对于任意字符串u,定义u的k-前缀为u_k = u[1..min(len(u), k)]。k-前缀...