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

题目链接

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

题目思路

这个题最容易的思想就是先进行排序,排序完从后往前数k位即可。这个时间复杂度为O(nlogn),但是我们其实没必要对整个数组进行完全的排序。
第二种方法的有化解有优先队列(大顶堆),我们维护大小为k的大顶堆,然后遍历完整个数组之后,我们的大顶堆中存放的是前k个最大的元素,我们一个一个取出来直到最后那个就行。
这样仍然是会涉及到堆的重排序问题,依然是O(nlogn)的时间复杂度,不过这个算法会比较容易想。
第三种方法就是直接使用快速排序的划分思想,因为我们快排每次划分后的中轴都是固定好位置的,而它的左边元素都比它小,右边元素都比它大。
我们可以利用这个思想,直接找到对应的中轴,而不需要去考虑剩余那些元素的相互间的有序性。

代码实现

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int left = 0;
        int right = nums.length - 1;
        int length = nums.length;
        //因为k一定存在,所以可以写永久循环
        while(true){
            //获取当前返回的下标
            int cur = helper(nums,left,right);
            //因为是第K大的元素,其下标就是length-k
            if(cur == length - k){
                return nums[cur];
            }else if( cur > length - k){
                right = cur - 1;
            }else{
                left = cur + 1;
            }
        }
    }

    private int helper(int[] nums, int l, int r){
        int left = l;
        int right = r;
        int flag = nums[left++];
        //这里一定要写小于等于,不然会把有序的数组变无序呜呜呜
        while(left <= right){
            //右边大于等于左手边flag位无所谓,重要的是还是得left<=right
            while(left <= right && nums[right] >= flag){
                right--;
            }
            //左手边不能出现和flag位相等的数据。
            while(left <= right && nums[left] < flag){
                left++;
            }
            //如果两个指针相与,直接跳出循环加快速度。
            if(left >= right){
                break;
            }
            int temp =  nums[right];
            nums[right] = nums[left];
            nums[left] = temp;
        }
        //交换浮标位和右指针位。
        nums[l] = nums[right];
        nums[right] = flag;
        return right;
    }
}

总结

这个题三个月前做过一次,今天每日一题又做了一次,虽然还是被边界条件卡了下,但是只WA了一次,比上次要好点。

快排分区的模板代码

    private int partition(int[] array, int start, int end) {
        int pivot = array[start];// 采用子序列的第一个元素作为枢纽元素
        while (start < end) {//
            // 从后往前在后半部分中寻找第一个小于枢纽元素的元素
            while (start < end && array[end] >= pivot) {
                --end;
            }
            // 将这个比枢纽元素小的元素交换到前半部分
            swap(array, start, end);
            // 从前往后在前半部分中寻找第一个大于枢纽元素的元素
            while (start < end && array[start] <= pivot) {
                ++start;
            }
            swap(array, start, end);// 将这个枢纽元素大的元素交换到后半部分
        }
        return start;// 返回枢纽元素所在的位置
    }
原文地址:https://www.cnblogs.com/ZJPaang/p/13207045.html