LeetCode 215.Kth Largest Element in an Array O(n)题解

快速选择算法

【题目】

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

For example,Given [3,2,1,5,6,4] and k = 2, return 5.

Note:

You may assume k is always valid, 1 ≤ k ≤ array's length.

【题解】

由于LeetCode对该题的时间复杂度要求不高,所以有多种解法,最简单的是直接将数组排序,然后输出第K大的数,根据不同的排序算法有不同的时间复杂度,最好的为O(nlogn)。但对于本题来说,该复杂度并不是最理想,利用快速选择算法,可将复杂度优化到O(n)。

介绍快速选择算法前有必要对快速排序做一定了解,因为快速选择算法中划分数组的过程跟快速排序算法是等同的。

【算法分析】

快速排序算法

这里我们直接引用数据结构与算法分析书上对快排的介绍。

As its name implies, quicksort is the fastest known sorting algorithm in practice. Its average running time is O(n log n).It is very fast, mainly due to a very tight and highly optimized inner loop. It has O(n2) worst-case performance(最坏情形的性能为O(N^2)), but this can be made exponentially unlikely with a little effort.

The quicksort algorithm is simple to understand and prove correct, although for many years it had the reputation of being an algorithm that could in theory be highly optimized but in practice was impossible to code correctly (no doubt because of FORTRAN).

Like mergesort, quicksort is a divide-and-conquer recursive algorithm(像归并排序一样,快速排序也是一种采取分治方法的递归算法). The basic algorithm to sort an array S consists of the following four easy steps(通过下面的4个步骤将数组S排序的算法如下):

1. If the number of elements in S is 0 or 1, then return(如果S中元素个数是0或1,则返回).
2. Pick any element v in S. This is called the pivot(取S中任一元素v,作为枢纽元).
3. Partition S - {v} (the remaining elements in S) into two disjoint groups(枢纽元v将S中其余的元素分成两个不想交的集合): S1 = {x(- S-{v}| x <= v}, and S2 = {x(- S-{v}| x >= v}.
4. Return { quicksort(S1) followed by v followed by quicksort(S2)}.

至于具体的代码这里不做展示,因为并不是本篇博客的重点,具体可看百度百科对快排的介绍,附上链接点击打开链接

快速选择算法

书中对快速选择算法的介绍如下:

Since we can sort the file in O(nlog n) time, one might expect to obtain a better time bound for selection. The algorithm we present to find the kth smallest element in a set S is almost identical to quicksort. In fact, the first three steps are the same. We will call this algorithm quickselect(叫做快速选择). Let |Si| denote the number of elements in Si(令|Si|为Si中元素的个数). The steps of quickselect are:

1. If |S| = 1, then k = 1 and return the elements in S as the answer. If a cutoff for small files is being used and |S| <=CUTOFF, then sort S and return the kth smallest element.
2. Pick a pivot element, v (- S.(选取一个枢纽元v属于S)
3. Partition S - {v} into S1 and S2, as was done with quicksort.(将集合S-{v}分割成S1和S2,就像我们在快速排序中所作的那样)
4. If k <= |S1|, then the kth smallest element must be in S1. In this case, return quickselect (S1, k). If k = 1 + |S1|, then the pivot is the kth smallest element and we can return it as the answer. Otherwise, the kth smallest element lies in S2, and it is the (k - |S1| - 1)st smallest element in S2. We make a recursive call and return quickselect (S2, k - |S1| - 1). (如果k<=|S1|,那么第k个最小元素必然在S1中。在这种情况下,返回quickselect(S1,k)。如果k=1+|S1|,那么枢纽元素就是第k个最小元素,即找到,直接返回它。否则,这第k个最小元素就在S2中,即S2中的第(k-|S1|-1)个最小元素,我们递归调用并返回quickselect(S2,k-|S1|-1))

由于本题是选择第k大的数,所以在实现上述算法时应注意在传入函数时应将k赋值为[S]-k,代码如下:

【代码】

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        int nSize = nums.size();  
        if (nSize == 1)
            return nums[0];  
        return QuickSelect(nums, 0, nSize - 1, nSize - k);
    }
    
    int QuickSelect(vector<int>& nums, int nBegin, int nEnd, int k) {
        int nKey = nums[nBegin];
        int i = nBegin, j = nEnd;
        while (i < j) {
            while (i < j && nums[j] >= nKey)
                j--;
            if (i < j)
                swap(nums[i], nums[j]);
            
            while (i < j && nums[i] <= nKey)
                i++;
            if (i < j)
                swap(nums[i], nums[j]);
        }
        
        if (i == k)
            return nums[i];
        if (i < k)
            return QuickSelect(nums, i + 1, nEnd, k);
        if (i > k)
            return QuickSelect(nums, nBegin, i - 1, k);
    }
    
    void Swap(int& a, int& b) {
        int nTmp = a;
        a = b;
        b = nTmp;
    }
};
对快速选择算法还想做更多了解的可参考该链接 点击打开链接


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值