Leetcode 215 算法 - 求数组中第K个最大元素 - 快速排序

这是力扣上一个中等难度的题目,题目是这样的

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。 =>  也就是说,对整个整数数组从大到小进行排序,数组下标为k-1的那个元素,就是我们需要的元素

[3,2,1,5,6,4], k = 2   => 数组中第1大的是6,第二大的是5,所以返回5

[3,2,3,1,2,4,5,5,6], k = 4  => 数组中第1大的是6,第2大的是5,第3大的是另一个5,第4大的是4, 所以返回4

所以,我们第一时间想到的解法就是对数组进行降序排序,排序完成后的数组中下标为k-1的那个元素,就是我们的答案

这道题如果不是考算法,只是平常的一道题,那么我们直接用数组内置sort方法很快就能解决,比如 

public class solution
{
    public int GetMaxKElement(int[] arr, int k)
    {
        Array.Sort(arr); // 对数组从小到大排序
        return arr[arr.Length - k];
    }
}

但是考算法,就需要我们自己写,我们用快速排序来实现,快速排序可以参考我之前写的一个算法  https://www.cnblogs.com/wphl-27/p/23114374

快速排序的核心主要是包括2点,一是 哨兵划分,二是递归

哨兵划分  - 以数组中某个元素(一般选第一个或最后一个元素)为基准,将所有小于该基准数的元素移动到其左边,所有大于该基准数的元素移动到其右边.

递归 - 对左子数组和右子数组递归执行哨兵划分,直到子数组长度为1时终止递归,从而完成整个数组的快速排序

我们来看一下数组 [2,4,1,0,3,5] 的快速排序流程

image

我们在快速排序的那个博客(https://www.cnblogs.com/wphl-27/p/23114374)中提到,时间复杂度是O(NLogN).  但是如果数组中包含大量的重复元素,每轮的哨兵划分都可能将数组划分了1和N-1两部分,这种情况下,快速排序的时间复杂度可能退化为O(N*N)  =>  这里的解决方案是使用 【三路划分】, 也就是说每轮将数组划分了3个部分: 小于,等于和大于基准数的所有元素.  =>  我们用C++中的vector来实现

#include <vector>
using std::vector;

class solution
{
   public:
           int FindKLarget(vector<int>& nums, int k)
           {
               return quickSelect(nums, k);
           }

    private:
          int quickSelect(vector<int>& nums, int k)
          {
            //选择基准数
            int pivot = nums.front();
            
            // 将数组分为大于基准数、小于基准数和等于基准数的三部分
            vector<int> big, small, equal;
            for(int num : nums)
            {
                if(num > pivot)
                    big.push_back(num);
                else if(num < pivot)
                    small.push_back(num);
                else
                    equal.push_back(num);
            }

            // 3部分数组划分好后,判断第K个元素落在哪部分,从而对该部分进行递归
            //比如big的size是5,K是4,那么原数组的第4大的元素,肯定会在big里面,因为big里面是原数组中前5个大的元素
            if(k <= big.size())
                return quickSelect(big, k);
            //k在small的size里面,那就说明big和equal的长度加起来都比K小(也就是原数组长度减去big长度),所以第K大的元素一定在small里面
            else if(k > nums.size() - big.size())
                return quickSelect(small,k);
            else  //第K大的元素在equal数组里面,直接返回
                return pivot;
          }  
};

 

posted on 2026-10-05 17:31  新西兰程序员  阅读(1)  评论(0)    收藏  举报