题解 | #寻找第K大#

寻找第K大

https://www.nowcoder.com/practice/e016ad9b7f0b45048c58a9f27ba618bf

import java.util.*;
public class Solution {
    public int findKth (int[] a, int n, int K) {
        //小顶堆
        PriorityQueue<Integer> q = new PriorityQueue<>((o1,o2)->o1.compareTo(o2));
        for(int i=0;i<K;++i){
            q.offer(a[i]);
        }
        for(int i=K;i<n;++i){
            if(q.peek()<a[i]){
                q.poll();
                q.offer(a[i]);
            }
        }
        int maxk=0;
        maxk = q.poll();
        return maxk;
    }
}

方法一:小顶堆

要求第k大元素,可以先求前k个最大元素,然后取最小,类比前一题的思想,用小顶堆可以求得前k个最大元素,然后堆顶就是第k大元素。

方法二:快排 + 二分查找

利用快速排序的思想,每次找到一个标杆元素,然后将小于它的值放右边,大于它的放左边,大的放左边原因是方便通过下标确定较大值的个数,然后分别递归左右两边,实现排序。在本题中,要求第k大,所以

  • 若比标杆元素大的个数等于k-1个,那么此标杆为第k大;
  • 若个数大于k-1个则说明第k大在左边,右边就不需要递归了;
  • 相反,若比标杆大的不足k-1个,说明第k大在标杆的右边,递归左边即可,右边不用管了。

步骤:

1、使用随机数获取标杆元素,防止数据分布导致每次划分不能均衡。将标杆位置的值与本区间的最左端交换,确保标杆在最左端。

2、确定好标杆的值、和两个负责遍历的指针位置

3、进行一次快排,即从右往左找到一个比标杆大的值,从左往右找到比标杆小的值,二者交换,双指针移动,重复操作,直到左指针大于右指针,说明找不到满足条件的值,跳出循环。

4、将右指针 j 所指的值与标杆处的值交换。

5、根据上面的分析,通过大于标杆的个数判断是否找到第k大的值,否则向左或向右区间递归。

6、重复上述步骤直到找到第k大为止。

import java.util.*;
public class Solution {
    public static void swap(int[] arr,int a, int b){
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
    Random r = new Random(); 
    public int partition(int[] a, int low, int high, int k){
        //随机快排划分,得到一个随机的标杆位置
        int x = Math.abs(r.nextInt()) % (high - low + 1) + low;
        swap(a,low,x);  //将标杆值放在本区间最左边
        int v = a[low]; //标杆值
        int i = low + 1; //从标杆的下一个位置开始
        int j = high; //
        while(true){
            //小于标杆的在右边
            while(j>low && a[j] < v){
                j--;
            }
            //大于标杆的在左边
            while(i<=high && a[i] > v){
                i++;
            }
            if(i>j){
                break;
            }
            swap(a,i,j);
		    i++;
            j--;
        }
        //交换标杆处与j位置的值
        swap(a,low,j);
        //左边为较大值,j从0开始,若左边的个数恰好为k-1个则标签值即为第k大
        if(j+1 == k){
            return a[j];
        }else if(j+1 < k){//左边个数不足k-1个
            return partition(a,j+1,high,k);
        }else{
            return partition(a,low,j-1,k);
        }
    }
    public int findKth (int[] a, int n, int K) {

        return partition(a,0,n-1,K);
    }
}

全部评论

相关推荐

不愿透露姓名的神秘牛友
07-18 18:23
点赞 评论 收藏
分享
盖茨伯爵:一样兄弟,我从4月开始发到现在了,都三四百个了
无实习如何秋招上岸
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务