zoukankan      html  css  js  c++  java
  • 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;// 返回枢纽元素所在的位置
        }
    
  • 相关阅读:
    [ARC 102D]All Your Paths are Different Lengths
    [NOI 2016] 优秀的拆分
    [TJOI 2015] 线性代数
    [LUOGU 4717] 快速沃尔什变换
    [NOI 2006] 最大获利
    Javascript继承机制的设计
    必应输入法产品分析
    你不得不知道的HTML5的新型标签
    Mobile Web
    10行代码爬取网页
  • 原文地址:https://www.cnblogs.com/ZJPaang/p/13207045.html
Copyright © 2011-2022 走看看