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

先来个暴力点的通用方法:

class Solution {
    public int findKthLargest(int[] nums, int k) {
        Arrays.sort(nums);
        return nums[nums.length-k];
    }
}

当然也可以采用PrioritQueue:

如果不明白优先队列:

优先队列中的元素可以按照任意顺序插入,却总是按照排序的顺序进行检索。也就是说,无论何时调用remove()\poll()方法,总会获得但当前优先队列中的最小元素。然而优先队列并没有对所有的元素进行排序。如果用迭代的范式处理这些元素,并不需要对他们进行排序。

优先队列使用了一个优雅且高效的数据结构,称为堆(heap)。堆是一个可以自我调整的二叉树,对树执行添加(add\offer)和删除(remove\poll)操作可以让最小的元素移动到根,而不必花费时间对元素进行排序。

哎呀说了这么多:反正priorityQueue这个数据结构 你无论remove、poll、删的是队中的最小(优先级最小)元素,无论什么时候peek的取的是队列中的最小(优先级最小)元素,无论你怎么加元素 add、offer 加后、这个队列一直保持有序、

class Solution {
    public int findKthLargest(int[] nums, int k) {
        Queue<Integer> q =new PriorityQueue<Integer>(k);
        for(int i =0;i<nums.length;i++){
            if(q.size()<k){      //将优先队列(k)填满
                q.offer(nums[i]);
            }else{
                if(nums[i]>q.peek()){  //peek总取出队列中最小元素
                    q.poll();          //poll总删除队列中最小元素;
                    q.offer(nums[i]);  //将这个元素加入队列
                }
            }
        }
        return q.peek();
    }
}

当然也可以使用快速排序:

class Solution {
    public void swap(int[] nums,int i,int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
    public int parrtion(int[] nums,int p,int r){
        int x = nums[r];
        int i = p-1;
        for(int j = p;j<r;j++){
            if(nums[j]<x){
                i++;
                swap(nums,i,j);
            }
        }//end of for
        swap(nums,r,i+1);
        return i+1;
    }
    
    public void quicksort(int[] nums,int p,int r){
        if(p<r){
            int q = parrtion(nums,p,r);
            quicksort(nums,p,q-1);
            quicksort(nums,q+1,r);
        }
    }
    public int findKthLargest(int[] nums, int k) {
        quicksort(nums,0,nums.length-1);
        return nums[nums.length-k];
    }
}

可看的出来将数组分割为两部分的时候我们完全只考虑存在倒数第k大数的数组部分,而另一部分就不用去管了

优化后的快排思想:

class Solution {
    public void swap(int[] nums,int i,int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
    public int parrtion(int[] nums,int p,int r){
        int x = nums[r];
        int i = p-1;
        for(int j = p;j<r;j++){
            if(nums[j]>x){     //按从大到小排  排序后nums[k-1] 即为所求
                i++;
                swap(nums,i,j);
            }
        }//end of for
        swap(nums,r,i+1);
        return i+1;
    }
    
    public int  quicksort(int[] nums,int p,int r,int k){
        if(p>=r) return nums[p];
        
        int q = parrtion(nums,p,r);
        if(q ==k-1) return nums[q];//如果找到k-1位置 返回第k大的数
        else if(q>=k){    //如果q>=k说明第k大的数在数组左半部分
            return quicksort(nums,p,q-1,k);//只在左边找就可以了
        }else{
             return quicksort(nums,q+1,r,k);//在右边找
            }
           
           
       
        
    }
    public int findKthLargest(int[] nums, int k) {
        return quicksort(nums,0,nums.length-1, k);
        
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值