Java——数组中第k个最大的元素

题目链接

leetcode在线oj题——数组中第k个最大的元素

题目描述

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

题目示例

输入: [3,2,1,5,6,4], k = 2
输出: 5

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

题目提示

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

解题思路

由于我们的题目要求时间复杂度为O(N),因此我们不能使用小根堆来解决这个问题(其时间复杂度为O(NlogN))

可以考虑使用快速排序来解决这个问题,其核心思想是,选定一个基准值,然后遍历整个数组,如果nums[i]比基准值小,那么就将nums[i]移动到基准值的左面,否则就移动到基准值的右边,将所有元素都遍历到后,基准值的位置就是排序好后的位置,我们就可以递归基准值的右侧的所有元素和基准值左侧的所有元素

需要注意的是,由于这道题是让我们找到数组中第k个最大的元素,因此当我们的基准值最后找到的位置是倒数第k个时,这时基准值就是数组中第k个最大的元素
如果我们选择数组中最左侧的元素作为基准值,假设数组十分特殊,本身是从大到小排列的,那么我们每一次递归都需要将基准值移动到最右侧,最终时间复杂度达到了O(N^2),因此我们不能草率的将最左侧或者最右侧的元素定义为基准值。在这里采用将最右侧元素和数组中随机一个元素互换位置后,再将最右侧元素作为基准值

详细代码

class Solution {
    public int findKthLargest(int[] nums, int k) {
        return quickSelect(nums, 0, nums.length - 1, nums.length - k);
    }

    private int quickSelect(int[] arr, int left, int right, int index) {
        int position = randomPartition(arr, left, right);
        if(position == index){
            return arr[position];
        } else {
            if(position < index){
                return quickSelect(arr, position + 1, right, index);
            } else {
                return quickSelect(arr, left, position - 1, index);
            }
        }
    }

    private int randomPartition(int[] arr, int left, int right) {
        Random random = new Random();
        int randomIndex = random.nextInt(right - left + 1) + left;
        swap(arr, randomIndex, right);
        return partition(arr, left, right);
    }

    private int partition(int[] arr, int left, int right) {
        int x = arr[right];
        int i = left - 1;
        for (int j = left; j < right; ++j) {
            if(arr[j] <= x){
                swap(arr, ++i, j);
            }
        }
        swap(arr, i + 1, right);
        return i + 1;
    }

    private void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

代码执行流程图

可以对照上面的代码来看一下流程图,这里选择的随机位置是1,对应的基准值为2
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值