数组中第k大的数 Kth Largest Element in an Array

问题:

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

For example,
Given [3,2,1,5,6,4] and k = 2, return 5.

Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.

解决:

① 找到第k大的数,可以存在重复。时间 O(NlogN) 空间 O(1)

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

② 使用优先队列,遍历数组时将数字加入优先队列(堆),一旦堆的大小大于k就将堆顶元素去除,确保堆的大小为k。遍历完后堆顶就是返回值。时间 O(NlogK) 空间 O(K)

class Solution {//18ms
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> p = new PriorityQueue<>();
        for (int i = 0;i < nums.length ;i ++ ) {
               p.add(nums[i]);
               if (p.size() > k) {
                   p.poll();
            }           
        }   
        return p.poll();
    }
}

③ 快速选择 Quick Select,跟快速排序一个思路。先取一个枢纽值,将数组中小于枢纽值的放在左边,大于枢纽值的放在右边,具体方法是用左右两个指针,如果他们小于枢纽值则将他们换到对面,一轮过后记得将枢纽值赋回分界点。如果这个分界点是k,说明分界点的数就是第k个数。否则,如果分界点大于k,则在左半边做同样的搜索。如果分界点小于k,则在右半边做同样的搜索。时间 Avg O(N) Worst O(N^2) 空间 O(1)。

class Solution { //5ms
    public int findKthLargest(int[] nums, int k) {
        return quickSelect(nums,k - 1,0,nums.length - 1);
    }
    public int quickSelect(int[] nums,int k,int left,int right){
        int pivot = nums[(left + right) / 2];
        int orgL = left;
        int orgR = right;
        while(left <= right){
            while(nums[left] > pivot){//从左到右找到第一个小于枢纽值得数
                left ++;
            }
            while(nums[right] < pivot){//从右向左找到第一个大于枢纽值的数
                right --;
            }
            if (left <= right) {//交换两个数
                swap(nums,left,right);
                left ++;
                right --;
            }
        }
        //最后退出的情况应该是右指针在左指针左边一格
        //这时如果右指针还大于等于K,说明第k个数在左半边
        if (orgL < right && k <= right) {
            return quickSelect(nums,k,orgL,right);
        }
        if (left < orgR && k >= left) {
            return quickSelect(nums,k,left,orgR);
        }
        return nums[k];
    }
    public void swap(int[] nums,int i,int j){
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

【注意】

  • dfs函数的kk-1,因为我们下标从0开始的,我们要比较k和下标,来确定是否左半部分有k个数字。

  • 互换左右时,也要先判断left <= right

转载于:https://my.oschina.net/liyurong/blog/1575541

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值