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 ≤ 数组的长度。

方法1:直接使用sort函数进行排序
主要思路:
(1)题目没有要求不能使用sort,所以直接使用了sort排序,然后使用反向迭代器查询第k大的数;
(2)但题目应该不是希望这样做的

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end());
        auto it=nums.rbegin();//反向迭代器
        while(--k){
            ++it;
        }
        return *it;//返回结果值
    }
};

方法2:使用分治
主要思路:
(1)这里只是要找第k大的元素,也就是说,使用快速排序的方法,没必要对整个数组进行排序,只需要使用快速排序的思路,找到第 k 大的元素既可;
(2)这样,每一次选择数组中的一个元素作为分割点,然后将大于该元素的元素放到其后面,小于等于该元素的元素放大其前面,这样在遍历一遍后,就找到了该分割点在数组中的正确的位置;
(3)然后,比较该位置是否是需要的第 k 大的元素的位置,若是,则返回结果,若不是,则根据第 k 大的元素在分割点的前面,还是后面,进一步减少搜索范围,进行下一轮的搜索;
(4)在找分割点时,为了避免一些极端的情形,可以对分割点进行随机的选择,既 swap(nums[left], nums[rand() % (right - left + 1) + left]); 在LeetCode中,实测是可以提高速度;
(5)注意分割过程中的标志之间的大小关系;

class Solution {
public:
    int find_index(vector<int>& nums,int left,int right){
    	//实现随机选择分割点,避免极端的情形
        swap(nums[left], nums[rand() % (right - left + 1) + left]);
        //要作为分割点的数
        int pivot=nums[left];
        while(left<right){
            while(left<right&&nums[right]>pivot){//保证右侧是大于分割点的数
                --right;
            }
            nums[left]=nums[right];//将不满足要求的数值放入左侧
            while(left<right&&nums[left]<=pivot){//保证左侧是小于分割点的数
                ++left;
            }
            nums[right]=nums[left];//将不满足要求的点放入右侧
        }
        nums[left]=pivot;//找到分割点的位置
        return left;
    }

    int findKthLargest(vector<int>& nums, int k) {
        int target=nums.size()-k;//k在升序序列中对应的索引值
		//左右边界
        int left=0;
        int right=nums.size()-1;
		
        while(left<=right){
            int pos=find_index(nums,left,right);//找出一个分割点的位置
            if(pos==target){//判断当前分隔点是否是需要的位置
                return nums[pos];
            }
            //根据分割点和要找的位置的关系,更新新的搜索范围
            if(pos<target){
                left=pos+1;
            }
            else if(pos>target){
                right=pos-1;
            }
        }
        return nums[left];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值