寻找第k大

寻找第k大-笔记

  • 题目提示使用快速排序的思想找到一个数组中第k大的数。
  • 思路:
    • 快排思想:使用快排的思想,就是将数组按照基准值划分为左右两边,左边大于基准,先进行一次快排,基准防止的位置为p,将大于基准的值放在前半部分,小于基准的值放在后半部分。大于基准的值有p-left个。所以此时如果p-left+1==k表示此时基准就是第k大的数。如果p-left+1 < k说明第k大在后半段(此时要找后半段中第k-(p-left+1))大的值,如果p-left+1 > k则说明第k大在前半段。但是这代码在牛客上超时了。
    • 使用堆排序,只交换k次堆顶和末尾元素,然后返回第k大的元素。

代码

  • 快排思想
class Solution {
public:
  
    int findpivot(vector<int> &nums,int left,int right){
        int i=left,j=right;
        int pivot=nums[left];
        while(left<right){
            while(left<right && nums[right]<pivot){
                right--;
            }
            nums[left]=nums[right];
            
            while(left<right && nums[left]>=pivot){
                left++;
            }
            nums[right]=nums[left];
        }
        int res=0;
        nums[left]=pivot;
        return left;
    }
    
    int dofind(vector<int>& nums,int left,int right,int k){
        
        int p=findpivot(nums,left,right);
        if(p-left+1==k){
            return nums[p];
        }
        else if(p-left+1>k){
            //说明在左半段
            return dofind(nums,left,p-1,k);
        }
        
        //说明在右半段
        return dofind(nums,p+1,right,k-(p-left+1));
    }
    int findKth(vector<int> a, int n, int K) {
        // write code here
        //使用快速排序的思想,先进行一次快排,基准防止的位置为p,将大于基准的值放在前半部分,小于基准的值放在后半部分。大于基准的值有p-left个。
        //所以此时如果p-left+1==k表示此时基准就是第k大的数。如果p-left+1<k说明第k大在后半段(此时要找后半段中第k-(p-left+1))大的值,如果p-left+1>k则说明第k大在前半段。
        
        int left=0,right=n-1;
        return dofind(a,left,right,K);
    
    }
};
  • 堆排序,使用大根堆。
class Solution {
public:
    
    void adjust(vector<int>& nums,int start,int last){
        //从第一个非叶子节点开始,从右至左,从上至下开始调整堆,直到父节点大于两个孩子节点。
        int maxchild=2*start+1;
        while(maxchild<=last){
            if(maxchild+1<=last && nums[maxchild]<=nums[maxchild+1]){
                maxchild+=1;
            }
            
            if(nums[start]<nums[maxchild]){
                swap(nums[start],nums[maxchild]);
                start=maxchild;
                maxchild=2*start+1;
            }
            else{
                return;
            }
        }
    }
    void heapfy(vector<int>& nums){
        int n=nums.size()-1;
        for(int i=(n-1)/2;i>=0;i--){
            adjust(nums,i,n);
        }
    }
    int findKth(vector<int> a, int n, int K) {
        // write code here
        //建堆
        n=n-1;
        heapfy(a);
        for(int i=n;i>=n-K;i--){//交换k次
            swap(a[0],a[i]);
            adjust(a,0,i-1);
        }
        return a[n-K+1];//得到第k大的数
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值