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

题目链接:数组中第K大元素

题目描述:
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

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

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

题目分析:TOP K问题,直接套堆模版即可

代码:

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int n = nums.length;
        int[] tree = new int[n+1];
        for(int i = 1;i <= n;i++)
            tree[i] = nums[i-1];
        //建立一个大顶堆
        for(int i = n/2;i >= 1;i--){
            shiftdown(tree,i,n);
        }
        //做k-1次删除即可
        while(k-->1){
           swap(tree,1,n);
           n--;
           shiftdown(tree,1,n);
        }
        return tree[1];
    }
    public void swap(int[] tree,int x,int y){
       int te = tree[x];tree[x] = tree[y];tree[y] = te;
    }
    //自上向下调整
    public void shiftdown(int[] tree,int i,int n){
       int pos = i;
       boolean f = false;
       while(!f&&i*2<=n){
          if(tree[i]<tree[i*2]){//如果小于左子树
              pos = i*2;
          }else  {
              pos = i;
          }
          if(i*2+1<=n&&tree[pos]<tree[i*2+1]){//如果小于右子树
            pos = i*2+1;
        } 
        if(pos!=i){//交换,并继续向下调整
            swap(tree,pos,i);
            i = pos;
        }else{//否则不调整退出循环
            f = true;
        }
       }
    }
}

上个思路是做k-1次删除,实质就是进行了一次堆排序,还有一种方法,我们维护一个前 k 个最大元素小顶堆,然后将数组元素不断插入,如果比堆顶元素小就跳过,如果大则替换堆顶元素,并重新调整,最后得到的堆顶元素即第k大的元素,只需将代码稍作调整即可

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int n = k;
        int[] tree = new int[n+1];
        for(int i = 1;i <= n;i++)
            tree[i] = nums[i-1];
        //建立一个大小为k的小顶堆
        for(int i = n/2;i >= 1;i--){
            shiftdown(tree,i,n);
        }
        //维护一个前k个最大元素小顶堆
        for(int i = k;i < nums.length;i++){
            if(nums[i]>tree[1]){//大于堆顶则删除堆顶并重新调增
                tree[1] = nums[i];
                shiftdown(tree,1,n);
            }
        }
        return tree[1];
    }
    public void swap(int[] tree,int x,int y){
       int te = tree[x];tree[x] = tree[y];tree[y] = te;
    }
    //自上向下调整
    public void shiftdown(int[] tree,int i,int n){
       int pos = i;
       boolean f = false;
       while(!f&&i*2<=n){
          if(tree[i]>tree[i*2]){//如果大于左子树
              pos = i*2;
          }else  {
              pos = i;
          }
          if(i*2+1<=n&&tree[pos]>tree[i*2+1]){//如果大于右子树
            pos = i*2+1;
        } 
        if(pos!=i){//交换,并继续向下调整
            swap(tree,pos,i);
            i = pos;
        }else{//否则不调整退出循环
            f = true;
        }
       }
    }
}

还有快排的选择思路和基于快排改进的中位数算法,贴个链接吧,不写了
https://mp.weixin.qq.com/s/tYUcigO8b4y59Pg7v6imzw

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值