leetcode215-第k个最大元素(快速排序分区函数的衍生问题)

1.问题

求数组中第k个最大元素:给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

2.方法分析

      eg:示例2排序后:122334556,k=4,这里的第k(4)大元素说的是从最大往小数到的第四个元素,即输出4【即求排序后的倒数第k个元素】,而不是说输出从大往小的第四个不同元素3。

1)排序(nlogN

      将nums数组排序,取arr.length-k这个索引对应的元素即可。

提问:若现在要求时间复杂度<nlogn呢?

2)使用优先级队列(nlogK

      取大用小,先建立k个元素的最小堆,扫描一遍集合,就保存了前k个最大元素,此时取出堆顶元素即可。(堆顶元素就是要找的第k大的元素)

3)使用快排的分区函数(O(n)

      要求一个集合的第k大元素,恰好就是集合排序后的第n-k个索引位置的值,分区函数不就是在返回排序后的最后索引吗?每划分区间一次元素就确定了该元素位置且返回了该元素对应索引位置,若这个索引恰好等于n-k位置索引,那么问题直接解决。

3.代码实现

基于快排分区函数的代码实现

public class Num251_FindKLargest {
    private  Random random=new Random();
    public  int findKthLargest(int[] nums, int k) {
        //利用快排分区函数,在分区时找到分区后元素索引与nums.length-k索引相同时的值,这个值就是要找的值
        //返回最大元素
        //nums.length-k:倒数第k个位置;第k个最大元素就是排序后倒数第nums.length-k的元素
        if(k>nums.length){
            throw new NoSuchElementException("illegal k,error");
        }
        return quickSortSelect(nums,0,nums.length-1,nums.length-k);
    }
    //选择是否进行排序,==情况不用排序了直接返回值即可,此题主要是求值
    private  int quickSortSelect(int[] nums, int l, int r, int index) {
        //如果index和返回的分界点的索引相同,就不用继续快排了
        int p=partition(nums,l,r);//返回分界点索引
        if(p==index){
            return nums[p];
        }
        //排序好的分区点索引不等于倒数第k个索引index
        //分区点下标<index,递归右区间,>index递归左区间
        return p<index?quickSortSelect(nums,p+1,r,index):quickSortSelect(nums,l,p-1,index);
    }
    //nums[l...r]进行排序
    private  int partition(int[] nums, int l, int r) {
        int randomIndex=random.nextInt(r-l+1)+l;
        swap(nums,l,randomIndex);
        int v=nums[l];
        //nums[l+1...j]<v
        //nums[j+1...i)>=v
        int j=l;
        //i时当前正在遍历元素
        for (int i = l+1; i <= r ; i++) {
            if(nums[i]<v){
                swap(nums,i,j+1);
                j++;
            }//else只需要i++,条件里已经写了
        }
        //循环完毕一次分区就分好了,交换l与j索引位置元素(j位置是<v的最后一个元素)
        swap(nums,l,j);
        return j;
    }

    private  void swap(int[] nums, int i, int j) {
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值