数组中的第K个最大元素

总结

方法一:暴力法

要找到数组中的第K个最大元素,首先可以想到排序,再遍历。

此种方法的时间复杂度最低为O(nlogn)。

方法二:基于partition的分治法

首先可以想到快速排序可以找到第index大的元素。

时间复杂度为O(n)。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int len = nums.length;
        if (k > len) {
            return 0;
        }

        int start = 0;
        int end = len - 1;
        int index = partition(nums, start, end);

        while (index != len-k) {
            if (index > len-k) {
                end = index-1;
                index = partition(nums, start, end);
            } else if (index < len-k) {
                start = index+1;
                index = partition(nums, start, end);
            }
        }

        return nums[index];
    }

    // partition函数是为了找出nums[0]在排序中的第几个位置
    public int partition(int[] nums, int start, int end) {
        int i = start;
        int j = end;
        int pivot = nums[start];

        if (i >= j) {
            return i;
        }

        while (i < j) {
            while (pivot <= nums[j] && i < j) {
                j--;
            }
            while (pivot >= nums[i] && i < j) {
                i++;
            }
            //如果满足条件则交换
            if (i < j) {
                int temp = nums[j];
                nums[j] = nums[i];
                nums[i] = temp;
            }
        }
        nums[start] = nums[i];
        nums[i] = pivot;

        return i;
    }
}

方法三:基于最小堆/优先队列的方法

可以建立一个大小为k的最小堆。堆里面的数字都是大数,如果有比最小值大的,则删除最小值,插入该数。如果比堆顶元素小,则i++。遍历完数组,堆顶元素为第k大的。在java中,我们通常用优先队列来表示堆。

在最小堆中,根节点的值总是大于它的子树中任意节点的值。于是可以在O(1)时间内得到已有的k个数字中的最大值。最大堆中创建的时间复杂度是O(nlogk),最大堆中插入的时间复杂度是O(logk),最大堆中删除的时间复杂度为O(logk)。可以在O(1)时间内得到已有的k个数字中的最大值,但需要O(logk)时间完成删除及插入操作。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        // 新建一个比较器,用该比较器实现一个优先队列
        Comparator<Integer> queueComparator = new numComparator();
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(k, queueComparator);

        for (int i = 0; i < nums.length; i++) {
            if (priorityQueue.size() < k ) {
                priorityQueue.add(nums[i]);
            } else if (nums[i] > priorityQueue.peek()) {
                // 如果有比最小值大的,则删除最小值,插入该数
                priorityQueue.remove();
                priorityQueue.add(nums[i]);
            }
        }

        return priorityQueue.peek();
    }

    // 此Comparator类用于确定上述PriorityQueue的排序顺序。
    class numComparator implements Comparator<Integer> {
        @Override
        public int compare(Integer x, Integer y) {
            if (x < y) {
                return -1;
            } else if (x > y) {
                return 1;
            }
            return 0;
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值