面试前必刷 数组中的第K个最大元素/TOPK问题 排序

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

题目来源: 力扣


快速排序

递归部分

当前基准元素的排名

如果不是第K就继续快排,一次排除一半

    //快速排序
    private int quickSort(int left,int right){
        int q=randomPartition(left,right);
        //找到第K大即返回
        if(q==index){
            return a[q];
        }else{
            return q<index?quickSort(q+1,right):quickSort(left,q-1);
        }
    }

寻找随机数部分

在范围内随机找一个数,把他换到最右边作为基准

    //选择随机位置作为标的
    private int randomPartition(int left,int right){
        int i=r.nextInt(right-left+1)+left;
        // 把标记放在最右边作为标的
        swap(right,i);
        // 返回标的所在的位置
        return partition(left,right);
    }

排序部分

最右边为基准,从左到右遍历,小的放在左边,最后把基准放在合适的位置

返回基准位置(排名)

    //排序
    private int partition(int left,int right){
        int x=a[right],i=left;
        for(int j=left;j<=right;j++){
            if(a[j]<x){
                swap(j,i++);
            }
        }
        // 把标的放在适合的位置
        swap(right,i);
        // 返回标的位置
        return i;
    }

代码

class Solution {
    Random r=new Random();
    int index;//目标位置
    int l;//数组长度
    int[] a;//数组
    public int findKthLargest(int[] nums, int k) {
        a=nums;
        l=nums.length;
        index=l-k;
        return quickSort(0,l-1);
    }

    //快速排序
    private int quickSort(int left,int right){
        int q=randomPartition(left,right);
        //找到第K大即返回
        if(q==index){
            return a[q];
        }else{
            return q<index?quickSort(q+1,right):quickSort(left,q-1);
        }
    }

    //选择随机位置作为标的
    private int randomPartition(int left,int right){
        int i=r.nextInt(right-left+1)+left;
        // 把标记放在最右边作为标的
        swap(right,i);
        // 返回标的所在的位置
        return partition(left,right);
    }

    //排序
    private int partition(int left,int right){
        int x=a[right],i=left;
        for(int j=left;j<=right;j++){
            if(a[j]<x){
                swap(j,i++);
            }
        }
        // 把标的放在适合的位置
        swap(right,i);
        // 返回标的位置
        return i;
    }

    // 交换
    private void swap(int i,int j){
        int temp=a[i];
        a[i]=a[j];
        a[j]=temp;
    }
}

海量数据下,面试官更希望你会堆排序

所以这题还可以用最小堆来做

堆排序

主函数

前K个数用上浮操作

后面的数如果比最小堆最小(堆顶)大就替换,并做下沉操作

    private int k;
    public int findKthLargest(int[] nums, int k) {
        this.k = k;
        for(int i=0;i<k;i++){
            up(nums,i);
        }
        int n = nums.length;
        for(int i=k;i<n;i++){
            if(nums[i]>nums[0]){
                swap(nums,0,i);
                down(nums,0);
            }
        }
        return nums[0];
    }

堆的操作

上浮:和父亲比较,如果比父亲小就换

下沉:和儿子比较,和最小的儿子换(如果父亲比它大)

    private void up(int[] nums,int index){
        if(index==0)return;
        int father = (index-1)/2;
        if(nums[father]>nums[index]){
            swap(nums,father,index);
            up(nums,father);
        }
    }
    private void down(int[] nums,int index){
        int left=2*index+1,right=left+1,small=index;
        if(left<k && nums[left]<nums[small]){
            small=left;
        }   
        if(right<k && nums[right]<nums[small]){
            small=right;
        }
        if(small!=index){
            swap(nums,small,index);
            down(nums,small);
        }
    }

代码

class Solution {
    private int k;
    public int findKthLargest(int[] nums, int k) {
        this.k = k;
        for(int i=0;i<k;i++){
            up(nums,i);
        }
        int n = nums.length;
        for(int i=k;i<n;i++){
            if(nums[i]>nums[0]){
                swap(nums,0,i);
                down(nums,0);
            }
        }
        return nums[0];
    }
    private void up(int[] nums,int index){
        if(index==0)return;
        int father = (index-1)/2;
        if(nums[father]>nums[index]){
            swap(nums,father,index);
            up(nums,father);
        }
    }
    private void down(int[] nums,int index){
        int left=2*index+1,right=left+1,small=index;
        if(left<k && nums[left]<nums[small]){
            small=left;
        }   
        if(right<k && nums[right]<nums[small]){
            small=right;
        }
        if(small!=index){
            swap(nums,small,index);
            down(nums,small);
        }
    }
    private void swap(int[] nums,int a,int b){
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值