数组中的第K个最大元素

https://leetcode-cn.com/problems/kth-largest-element-in-an-array/

 

215. 数组中的第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 ≤ 数组的长度。

 

问题思路:数组中的第K个最大元素可以借用快排的思路,通过匹配哨兵位置进行左右查找,相当于半分治(只递归一半,并非整个原问题分解为子问题)。

1.通过快排思路,校正第一个哨兵的位置(左侧元素小于哨兵,右侧元素大于哨兵),通过比较哨兵的位置,来确定递归(分治)方向。

2.将原问题在整个区间找到哨兵的位置分解为在子区间找到对应哨兵的位置。

3.当哨兵的位置恰好为第k大位置时,返回哨兵的值。

 

代码设计思路

1.因为设计的分治思路(分治方向只往正确的方向走,也就是单通道,一直在重复一条递归道路,即最深的递归层的返回值可以返回至最外层。也就是说可以值返回一个结果,因此无需比较众多的返回值结果)。设计递归出口,当哨兵位置恰好准确时,返回哨兵取值。否则分解为对应左右区间的子问题。

2.分解的区间为哨兵的左右区间,因此递归区间无需加入哨兵位置。

 

# 本题遇到bug,在借鉴快排思路时,只进行的左右各一次的填坑。并没有结束第一轮填坑操作。所以,需要注意在使用快排时,最外层需要while(i<j)以便完成整轮快排。

 

 

class Solution {
public:
    // 快排思路做分治。
    // 设置哨兵,归位哨兵,哨兵位置则为该哨兵的第k大位置。
    // 根据哨兵位置,大于哨兵右分治,小于哨兵左分治。等于哨兵则返回结果。
    int dfs(vector<int>& nums, int k, int l, int r){
        //哨兵  填坑法
        int index = nums[l];
        int i = l;
        int j = r;
        while(i<j){
            while(i<j&&nums[j]>=index){
                j--;
            }
            nums[i] = nums[j];
            while(i<j&&nums[i]<=index){
                i++;
            }
            nums[j] = nums[i];
        }
        nums[i] = index;
        // 需要返回第k大的数字,
        //当恰好为哨兵时,返回改位置的数值
        // cout<<index<<" "<<i<<" "<<nums.size()-i<<" "<<nums.size()<<endl;
        int index__ = nums.size()-i;
        if(k==(index__))
            return nums[i];
        else if(k>(index__))
            return dfs(nums, k, l, i-1);
        else if(k<(index__))
            return dfs(nums, k, i+1, r);

        return 0;
    }

    int findKthLargest(vector<int>& nums, int k) {
        int ans = dfs(nums, k, 0, nums.size()-1);
        return ans;
    }
};

 

posted @ 2021-06-22 22:03  会飞的雅蠛蝶  阅读(192)  评论(0编辑  收藏  举报