【C++、快速排序巧用】LeetCode215 数组中的第K个最大元素

  1. 数组中的第K个最大元素

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4

说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

方法一

采用快速排序的思想,随机选取一个值作为分割线,分割线左边的都不比这个值大,分割线右边都比这个值大。

只需要比较分割线的索引值n-k的值(目标值)
如果目标点正好等于分割点,说明此时的分割点正是要找的第K大的值;
如果目标点在分割点右侧,说明左侧区间有待缩减掉,仅对右半边递归;
如果目标点在分割点左侧,说明右侧区间有待缩减掉,仅对左半边递归。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        return findKthLargest(nums, 0, nums.size()-1, k);
    }
private:
    int findKthLargest(vector<int>& nums, int low, int high, int k){
        int n=nums.size();
        int index = partition(nums, low, high);
        if(index==n-k) return nums[index];
        else if(index < n-k) return findKthLargest(nums,index+1,high,k);
        else return findKthLargest(nums,low,index-1,k);
    }

    int partition(vector<int>& nums, int low, int high) {
        uniform_int_distribution<int> u(low, high);
        default_random_engine e;//生成无符号随机整数
        std::swap(nums[u(e)], nums[high]);//避免最糟糕的情况出现,随机选值放到最右端
        int i = 0, j = 0;
        for (i = low, j = low;j < high;++j) {//从头到尾遍历每个数,但不遍历最后的基准值
            if (nums[j] <= nums[high]) {//如果发现当前数不大于基准值
                std::swap(nums[i++], nums[j]);//把这个不大于基准值的数与i位置上的数交换,同时i++
            }
        }//结束后,i之前的所有的数都不大于基准值,i之后所有的数都大于基准值;退出的时候j=high
        std::swap(nums[i], nums[j]);//把j位置的数(基准值)换到i位置上来
        return i;
    }
};

后续方法参考:https://blog.csdn.net/lv1224/article/details/80112229

方法二(用STL的轮子nth_element())

使用STL库函数 nth_element(),通过调用nth_element(start, start+n, end) 方法可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素),并且比这个元素小的元素都排在这个元素之前,比这个元素大的元素都排在这个元素之后,但不能保证他们是有序的

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        nth_element(nums.begin(),nums.end()-k,nums.end());
        return *(nums.end()-k);
    }
};

方法三(用STL的轮子sort)

直接排序,取值

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end());
        return nums[nums.size()-k];
    }
};

方法四

利用 multiset 本身有序,维持 multiset 大小 K,则 multiset 首元素即为所求。
注意: 由于数组本身存在重复元素,所以这里要用multiset。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        multiset<int> s;
        for(auto &m:nums){
            s.insert(m);
            if(s.size()>k) s.erase(s.begin());
        }
        return *s.begin();
    }
};
原创文章 97 获赞 33 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qionggaobi9328/article/details/105707026
今日推荐