LeetCode第215 数组中的第K个最大元素

题目来源

题目描述

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
在这里插入图片描述

解题思路

1、这道题如果是调用库函数,三行代码就求出

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

2、不使用库函数,使用快排思路
使用快排的思路:
(1)设置一个中心点pivot,将数组中小于或等于pivot的数放在数组的左边,将大于pivot的数放在数组的右边

Put numbers < pivot to pivot's left
Put numbers > pivot to pivot's right

(2)会有三种情况:(寻找第k个最大元素)

  • 中心点pivot的索引值刚好为k,此时返回nums[k]
  • 如果中心点pivot的索引值比k小,继续搜索中心点的左边
  • 如果中心点pivot的索引值比k大,继续搜索中心点的右边
if indexOfPivot == k, return A[k]
else if indexOfPivot < k, keep checking left part to pivot
else if indexOfPivot > k, keep checking right part to pivot

3、代码逻辑:
求解第k个最大元素,这里使用快排的思路,可以理解为求解第(nums.length - k)个最小元素。不需要 将数组全部排好序,只需要设置一个哨兵(中心点)。
在这里插入图片描述

代码快排
class Solution {
    public int findKthLargest(int[] nums, int k) {
        return findKthLargest(nums, 0, nums.length - 1, nums.length - k);
    }
    public int findKthLargest(int[] nums, int start, int end, int k){
        int pivot = nums[end];
        int left = start;
        //for循环找出不大于nums[end]的数,其索引值为0-left
        for(int i = start; i < end; i++){
            if(nums[i] <= pivot)
                swap(nums, left++, i);
        }
        swap(nums, left, end);
        
        if(left == k)
            return nums[left];
        else if(left < k)
            return findKthLargest(nums, left + 1, end, k);
        else
            return findKthLargest(nums, start, left - 1, k);
    }
    void swap(int[] nums, int i, int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    } 
}
代码2
class Solution {
    public int findKthLargest(int[] nums, int k) {

        final PriorityQueue<Integer> pq = new PriorityQueue<>();
        for(int val : nums){
            pq.offer(val);

            if(pq.size() > k)
                pq.poll();
        }
        return pq.peek();
    }
}



class Solution {
    public int findKthLargest(int[] nums, int k) {
        
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        for(int i = 0 ; i < nums.length; i++){
            if(pq.size() < k)
                pq.offer(nums[i]);
            else if(nums[i] > pq.peek()){
                pq.poll();
                pq.offer(nums[i]);
            }
        }
        return pq.peek();

    }
}
代码3自己建堆
class Solution {
    public int findKthLargest(int[] nums, int k) {

        int heapSize = nums.length;
        for(int i = 0; i  < nums.length; i++){
            heapInsert(nums, i);
        }
        for(int i = nums.length - 1; i >= nums.length - k + 1; --i){
            swap(nums, 0, i);
            --heapSize;
            maxHeapify(nums, 0, heapSize);
        }
        return nums[0];

    }

    public void heapInsert(int[] arr, int index){
        while(arr[index] > arr[(index - 1) / 2]){
            swap(arr, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }

    public void maxHeapify(int[] arr, int index, int size){
        int left = index * 2 + 1;

        while(left < size){
            int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
            largest = arr[largest] > arr[index] ? largest : index;
            if(largest == index)
                break;
            swap(arr, largest, index);
            index = largest;
            left = index * 2 + 1;
        }
    }

    public void swap(int[] a, int i, int j){
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

参考:https://leetcode.com/problems/kth-largest-element-in-an-array/discuss/60333/Concise-JAVA-solution-based-on-Quick-Select
https://leetcode.com/problems/kth-largest-element-in-an-array/discuss/60312/AC-Clean-QuickSelect-Java-solution-avg.-O(n)-time

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值