leetcode O(n)找数组中第k个最大的元素,利用的是类似快速排序的写法,涉及到 Hoare 划分

class Solution {
public:
//这个快速选择算法,平均来说,是N+N/2+N/4.....到最后是2*N,也就是O(N)
//但是,如果是一个倒序的数组的话,那么还是最复杂的N^2
//这个写法中的严格小于是关键,可以应对多个复杂元素
//比如 1 1 1 1 ,如果是<=,>=的话,会把所有元素都划分到一边,然后复杂度还是N^2
int quickselect(vector<int>&nums,int l,int r,int k){
    if(l==r)return nums[k];//这里返回k的原因是,函数里面传入的参数是n-k,这个直接返回nums[k]
    //就是nums[n-k]了,因为传入的这个k就是n-k
    int par=nums[l],i=l-1,j=r+1;
    while(i<j){
        do i++; while(nums[i]<par);
        do j--; while(nums[j]>par);
        if(i<j)swap(nums[i],nums[j]);
    }
    //if(j<=k)return quickselect(nums,j,r,k);
    //else return quickselect(nums,l,j-1,k);
    /**
     * 这里,上下两种写法,看起来是一样的,但是,你这样写就会超时,举个例子
     * [2,1]数组,要找的是第0个元素,也就是传入的参数k是0
     * 交换后是[1,2],结束后j=0,j=0 <= k=0,
     * 然后就会调用quickselect(nums,0,1,k),你会发现,本来就是调用quickselect(nums,0,1,k)
     * 你现在用调用了一次,那不就又是原来那个吗,那递归调用就会一直进行,永远没有结束,
     */
    if (k <= j) 
    return quickselect(nums, l, j, k);      // 严格对应左区间 [l, j]
    else 
    return quickselect(nums, j + 1, r, k);  // 严格对应右区间 [j + 1, r]
} 
//就是O(n)找到倒数第k个的数字,在这个数组中
    int findKthLargest(vector<int> &nums, int k) {
        int n = nums.size();
        return quickselect(nums, 0, n - 1, n - k);
    }
};

这里的划分是 Hoare 划分,不可以微调!!不可以微调!!
image

posted @ 2026-05-31 20:31  Time_q  阅读(21)  评论(0)    收藏  举报