leetcode 215. 数组中的第K个最大元素【深入理解快速排序】

方法一:

理解题目很简单。思路很清晰。最慢的复杂度应该是O(nlogn)。

先排序,再查找。

执行用时 :16 ms, 在所有C++提交中击败了91.91%的用户

内存消耗 :9.4 MB, 在所有C++提交中击败了46.39%的用户

...你仿佛在逗我。这都可以超过90%。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end(),greater<int>());
        return nums[k-1];
    }
};

方法二:

能不能把时间复杂度降低到O(n)。

(1)首先,需要知道的是,这种最值问题肯定是需要完全遍历的。

 

想法一:如果维护一个长度为4的数组,如果来了一个元素大于最最末尾的,就往后移。那么实际上平均时间复杂度类似于冒泡排序。。
想法二:参考的题解。其中提到了用优先队列建立小跟堆的方法:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int,vector<int>,greater<int>> minstack(1,nums[0]);
        for(int i=1;i<nums.size();i++)
        {
            minstack.push(nums[i]);
            if(minstack.size()>k)
                minstack.pop();
        }
        return minstack.top();
    }
};

我寻思也没那么快:

执行用时 :20 ms, 在所有C++提交中击败了72.22%的用户

内存消耗 :9.6 MB, 在所有C++提交中击败了33.50%的用户

 

标准解法:

既然遍历所有元素是必要条件,那么:

类似快排的划分思路
先任取一个数,把比它大的数移动到它的左边,比它小的数移动到它的右边。移动完成一轮后,看该数的下标(从0计数),如果刚好为k-1则它就是第k大的数,如果小于k-1,说明第k大的数在它右边,如果大于k-1则说明第k大的数在它左边,取左边或者右边继续进行移动,直到找到。

这样时间复杂度虽然达不到O(n),但是比nlogn小很多。

执行用时 :40 ms, 在所有C++提交中击败了41.12%的用户

内存消耗 :10.1 MB, 在所有C++提交中击败了12.72%的用户

我对自己的快排深感怀疑。。。。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        return quickSort(nums,k,0,nums.size()-1);
    }
    int quickSort(vector<int>& nums, int k,int i,int j)//i,j是起始与终止的地方
    {
        //从大到小
        
        int s=i,e=j;//start,end
        //1.选取基准点tmp
        int tmp=nums[i];
        //2.开始移动
        while(i<j)
        {
            while(i<j)
            {
                if(nums[j]>tmp)
                {
                    nums[i]=nums[j];
                    break;
                }
                j--;
            }
            
            while(i<j)
            {
                if(nums[i]<tmp)
                {
                    nums[j]=nums[i];
                    break;
                }
                i++;
            }
        }
        nums[i]=tmp;//哨兵归位
        if(i+1-s==k)
        {
            return nums[i];
        }
        else if(i+1-s<k)//在后面
        {
            return quickSort(nums,k-i-1+s,i+1,e);
        }
        else//在前面
        {
            return quickSort(nums,k,s,i-1);
        }
        
    }
};

 别人家的快排

执行用时 :8 ms, 在所有C++提交中击败了99.86%的用户

内存消耗 :9 MB, 在所有C++提交中击败了96.58%的用户

下次抽时间钻研钻研。可能是自己的方法和思维还是有问题。

class Solution {
public:
   int findKthLargest(vector<int>& nums, int k) {
       int low = 0, high = nums.size() - 1, mid = 0;
       while (low <= high) {
           mid = partation(nums, low, high);
           if (mid == k - 1) return nums[mid];
           else if (mid > k - 1) high = mid - 1;
           else low = mid + 1;
       }
       //  实际上返回 -1 代表没有第 k 大的数,这里不存在
       return -1;
   }
   
   int partation(vector<int>& nums, int low, int high) {
       int left = low + 1, right = high;
       swap(nums[low], nums[(low + high) / 2]);
       int bound = nums[low];
       //  双指针,快速排序,交换不符合条件的数据
       while (left <= right) {
           while (left < high && nums[left] >= bound) left++;
           while (nums[right] < bound) right--;
           if (left < right) 
               swap(nums[left++], nums[right--]);
           else break;
       }
       //  将bound放到换分完成后的两个数组之间,作为边界, 返回bound的位次
       swap(nums[low], nums[right]);
       return right;
   }
};

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值