找出无序数组第K大/小数的方法(Leetcode 215)

上一篇博客讲解了找出无序数组中位数的方法,找无序数组第K大数的方法跟中位数的方法差不多,K值可以类比成中位数的值,所以方法还是差不多的,分别是1.排序+取值 2.快排思想 3.桶排序。上一篇博客详细讲了这三种方法。在这里附上上一篇博客的链接:找出无序数组中位数的方法
这里我们以Leetcode中215题为例进行讲解

1 排序+取值

这个方法就不多说了。

2 快排思想

这里主要说一下快排哨兵元素选取的问题。
一般快排选哨兵元素都是选区间第一个为哨兵,然后左右指针移动,因为这样写起来比较简单,但是经过我实验发现,选首元素为哨兵运行速度会非常慢!!! 这里附上我选首元素为哨兵元素的代码:

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int left=0,right=nums.length-1;
        int loc=quicksort(nums,left,right);
        int tarloc=nums.length-k;
        while(true)
        {
            if(loc==tarloc) break;
            else if(loc>tarloc) loc=quicksort(nums,left,loc-1);
            else loc=quicksort(nums,loc+1,right);
        }
        return nums[loc];
    }
    public int quicksort(int[] nums,int left,int right)
    {
        int target=nums[left];
        while(left<right)
        {
            while(left<right&&nums[right]>=target) right--;
            nums[left]=nums[right];
            while(left<right&&nums[left]<=target) left++;
            nums[right]=nums[left];
        }
        nums[left]=target;
        return left;
    }
}

附上运行速度:
在这里插入图片描述
我靠,真的是慢的要死啊。
我在讨论区看有人说哨兵元素改成中间元素会快很多,然后我又改了很长时间(因为选中间元素的话意味着哨兵元素最后的位置会不确定,所以需要以左右指针的位置确定继续往哪个区间找),最后还是参考着九章算法的解析完成的,在这里附上链接:九章算法
代码如下:

class Solution {
    public int findKthLargest(int[] nums, int k) {

        return quicksort(nums,0,nums.length-1,nums.length-k);
    }
    public int quicksort(int[] nums,int left,int right,int k)
    {
        if(left==right) return nums[left];
        int target=nums[(left+right)/2];
        int start=left,end=right;
        while(start<=end)
        {
            while(start<=end&&nums[start]<target) start++;
            while(start<=end&&nums[end]>target) end--;
            if(start<=end)
            {
                int temp=nums[start];
                nums[start]=nums[end];
                nums[end]=temp;
                start++; end--;
            }
        }
        if(end>=k&&end>=left) return quicksort(nums,left,end,k);
        else if(start<=k&&start<=right) return quicksort(nums,start,right,k);
        return nums[k];
    }
}

这次运行速度真的是快的飞起!
在这里插入图片描述

3 利用最小堆

这里只需要用一个小顶堆即可,存k个较大的数,当有数插入后,把堆顶元素去除,然后继续循环操作。
代码如下:

class Solution {
    public int findKthLargest(int[] nums, int k) {
        Queue<Integer> minHeap = new PriorityQueue<Integer>();
        Queue<Integer> maxHeap = new PriorityQueue<Integer>(new Comparator<Integer>(){
            public int compare(Integer o1,Integer o2){
                return o2-o1;
            }
        });
        for (int i=0;i<nums.length;i++)
        {
            minHeap.add(nums[i]);
            if(i>=k) minHeap.poll();
        }
        return minHeap.peek();
    }
}

不过时间方面不是很理想。
在这里插入图片描述

总结

以上就是三种找无序数组第K大数的方法,可以看出优化后的利用快排思想速度是最快的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值