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

方法一:

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

先排序,再查找。

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

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

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

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

方法二:

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

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

 

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

class Solution {
public:
    int findKthLargest(vector& nums, int k) {
        priority_queue,greater> minstack(1,nums[0]);
        for(int i=1;ik)
                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& nums, int k) {
        return quickSort(nums,k,0,nums.size()-1);
    }
    int quickSort(vector& nums, int k,int i,int j)//i,j是起始与终止的地方
    {
        //从大到小
        
        int s=i,e=j;//start,end
        //1.选取基准点tmp
        int tmp=nums[i];
        //2.开始移动
        while(itmp)
                {
                    nums[i]=nums[j];
                    break;
                }
                j--;
            }
            
            while(i

 别人家的快排

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

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

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

class Solution {
public:
   int findKthLargest(vector& 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& 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;
   }
};

 

你可能感兴趣的:(中等难度,leetcode)