力扣215题,数组中的第K个最大元素

力扣215题,数组中的第K个最大元素

题目描述

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

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

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

输入输出样例

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

解法一,暴力解法

//解法一不考虑时间复杂度
//时间复杂度为O(nlogn)
    int findKthLargest(vector<int>&nums,int k)
    {  
        if(nums.empty())
        {
            return NULL;
        }

        sort(nums.begin(),nums.end());

        int length=nums.size();
        return nums[length-k];
    }

时复 O(NlogN) 空复 O(logN)

解法二,使用快速排序,先排序再取值(三路排序)

//使用快速排序的思想完成

    int findKthLargest2(vector<int>&nums,int k)
    {
        quickSorts2(nums,0,nums.size()-1);

        return nums[nums.size()-k];        
    }

    // void quickSort(vector<int>&nums,int left,int right)
    // {
    //     if(left>=right)
    //     {
    //         return;
    //     }

    //     int pivotIndex=partition(nums,left,right);

    //     quickSort(nums,left,pivotIndex-1);
    //     quickSort(nums,pivotIndex+1,right);
    // }

    //划分在顺序数组和逆序数组上表现很差的
    //解决方法随机选择切分元素

    void randomPartiton(vector<int>&nums,int left,int right)
    {
        int i=left+rand()%(right-left+1);
        swap(nums,i,left);
    }

    void quickSorts2(vector<int>&nums,int left,int right)
    {   
        //当左边大于右边,那么就可以跳出循环
        if(left>=right)
        {
            return;
        }

        randomPartiton(nums,left,right);
        int pivot=nums[left];

        // 将pivot后面的元素划分成三个区间
        //all in nums[left+1,lt)<pivot;
        //all in nums[lt,i)=pivot;
        //all in nums(gt,right]>pivot;

        //设定边界的初始条件
        int lt=left+1;//lt=less than
        int gt=right; //gt= greater than
        int i=left+1;

        while(i<=gt)
        {
            //当元素小于当前划分的值时
            if(nums[i]<pivot)
            {
                //交换到等于pivot区间的第一个位置
                swap(nums,i,lt);
                lt++;
                i++;
            }
            else if(nums[i]==pivot)
            {
                //划分在第二个区间里
                i++;
            }
            else{
                 //划分到数组的末尾
                 swap(nums,i,gt);
                 gt--;   
            }
        }
        //交换 pivot
        swap(nums,left,lt-1);



        //继续递归进行排序
        quickSorts2(nums,left,lt-2);
        quickSorts2(nums,gt+1,right);
    }

    void swap(vector<int>&nums,int index1,int index2)
    {
        int temp=nums[index1];
        nums[index1]=nums[index2];
        nums[index2]=temp;
    }

解法三,借用快速排序进行减治的算法(双端)

void swap(vector<int>&nums,int index1,int index2)
    {
        int temp=nums[index1];
        nums[index1]=nums[index2];
        nums[index2]=temp;
    }


    //借用快速排序的思想,使用减治的方法
    //根据题意第k个元素,即代表要找到pivot恰好等于length-k;

    int findKthLargest3(vector<int>&nums,int k)
    {
        //初始化参数
        int length=nums.size();
        int left=0;
        int right=nums.size()-1;
        int target=length-k;

        //利用双路快排的思想寻找中枢

        while(left<=right)
        {
            int pivotIndex=partitionDouble(nums,left,right);
            if(pivotIndex==target)
            {
                return nums[pivotIndex];
            }
            else if(pivotIndex<target)
            {
                 left=pivotIndex+1;
            }
            else{
                
                right=pivotIndex-1;
            }
        }
    }

     int partitionDouble(vector<int>&nums,int left,int right)
     {
        //随机选取
        randomPartiton(nums,left,right);
        int pivot=nums[left];

        //设定两个区间
        //[left+1,le)<=pivot;
        //(ge,right]>=pivot;

        //初始化两个区间使得原始为空
        int le=left+1;
        int ge=right;

        while(true)
        {
            //le遇到比pivot大的停下来
            while(le<=ge&&nums[le]<pivot)
            {
                le++;
            }

            //ge遇到比pivot小的停息来
            while(le<=ge&&nums[ge]>pivot)
            {
                ge--;
            }

            if(le>=ge)
            {
                break;
            }

            //交换二者的值
            swap(nums,le,ge);
            le++;
            ge--;
        }

        //交换pivot
        swap(nums,left,ge);
        return ge;
     }

时复:O(n)

空复:O(logn)

解法四,借用堆排序的方法(最大堆)

 //使用堆排序的方法
    int findKthLargest4(vector<int>&nums,int k)
    {
        int heapSize=nums.size();
        //建立堆
        buildMaxHeap(nums,heapSize);

        //从最大堆剔除,并逐渐进行重建
        for(int i=nums.size()-1;i>=nums.size()-k+1;i--)
        {
            swap(nums,0,i);
            heapSize--;
            maxHeapiy(nums,0,heapSize);
        }
        return nums[0];
    }

    void buildMaxHeap(vector<int>&nums,int heapSize)
    {
        for(int i=heapSize/2;i>=0;i--)
        {
            maxHeapiy(nums,i,heapSize);   
        }
    }

    void maxHeapiy(vector<int>&nums,int i,int heapSize)
    {
        int left=i*2+1;
        int right=i*2+2;
        int largest=i;

        if(left<heapSize&&nums[left]>nums[largest])
        {
            largest=left;
        }

        if(right<heapSize&&nums[right]>nums[largest])
        {
            largest=right;
        }

        if(largest!=i)
        {
            swap(nums,i,largest);
            maxHeapiy(nums,largest,heapSize);

        }
    }

时复O(nlogn)

空复O(logn)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值