LeetCode刷题笔记(Kth Largest Element in an Array)

今天刷的题目思路非常清晰。

具体题目如下:

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

Example 1:

Input: [3,2,1,5,6,4] and k = 2
Output: 5
Example 2:

Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4
Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.

 解答如下:

先分析题意,题目的意思是在给定的一个无序数组中,找到第k大的数,这个k是人为输入的。

方法一

很容易想到的是,先将给定的数组排个序。由于要找到第几大的数,所以将数组按从大到小排序会更方便解决问题。这里为了方便起见,又直接用了库函数sort()进行排序,但是之前一直都是用的从小到大排序,所以经过网上的学习,一般有两种方式实现从大到小排序:第一种,从大到小(降序):sort(begin,end,greater<data-type>());从小到大(升序):sort(begin,end,less<data-type>());。第二种,改写cmp函数:bool cmp(int a,int b) {return a > b;},再用sort(begin,end,cmp);调用即可。由于存在限制,所以本文选择第一种方法进行降序排序。

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

  提交后的结果如下:

方法二

用priority_queue(优先队列)去存放nums,然后将队列中第k-1高优先权的元素进行删除,最后返回优先队列中有最高优先级的元素即第k大元素。

priority_queue是元素在队列尾追加,而从队列头删除。每次从队列中取出的是具有最高优先权的元素。它的“优先”意指取队首元素时,有一定的选择性,即根据元素的属性选择某一项值最优的出队。一般默认是大顶堆(数据越大,优先级越高),如果要用到小顶堆(数据越小,优先级越高),则一般要写入三个参数greater< >,如priority_queue<int>  greater<int> q(nums.begin(), nums.end()); 相反如果要用到大顶堆则一般要写入三个参数less< >。priority_queue常用的操作如下:①empty()  如果优先队列为空,则返回真  ②pop()  删除第一个元素  ③push()  加入一个元素  ④size()  返回优先队列中拥有的元素的个数  ⑤top()  返回优先队列中有最高优先级的元素。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int> q(nums.begin(), nums.end());//用优先队列保存nums,并没有排序
        for (int i = 0; i < k - 1; ++i) {
            q.pop(); //从队列中删除前k-1高优先权元素(标准库默认,数据越大,优先级越高)
        }
        return q.top(); //返回当前队列中优先级最高的元素,也即最大的元素。
    }
};

  提交后的结果如下:

方法三(推荐的解法)

采用快速排序Quick Sort的思想(这里排序的方向是从大往小排),它的核心思想:每次都要先找一个标定点pivot,然后遍历其他所有的数。像本题要从大到小排,就需把对于标定点pivot的数放到左半边,把小于标定点pivot的数放在右半边,这样标定点pivot是整个数组中第几大的数字就确定了,即使左右两部分不一定是完全有序的,也并不影响本题所需的结果。当求出了标定点pivot的位置,如果正好是k-1,那么直接返回该位置上的数;如果大于k-1,说明要求的数在左半部分,更新右边界,同理再求新的标定点pivot位置;反之则在右半部分,并更新左边界,同理再求标定点pivot的位置。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        int left = 0, right = nums.size() - 1;
        while (true) {
            int pos = partition(nums, left, right);
            if (pos == k - 1) return nums[pos];//如果第k大的元素就在标定点处,则直接返回nums[pos]
            else if (pos > k - 1) right = pos - 1;//如果第k大的元素就在标定点右边,则修改右边界,缩短区间            else left = pos + 1; //如果第k大的元素就在标定点左边,则修改左边界,缩短区间
        }
    }
    int partition(vector<int>& nums, int left, int right) {
        int pivot = nums[left], l = left + 1, r = right;
        while (l <= r) {
            if (nums[l] < pivot && nums[r] > pivot) {
                swap(nums[l++], nums[r--]);
            }
            if (nums[l] >= pivot) ++l;
            if (nums[r] <= pivot) --r;
        }
        swap(nums[left], nums[r]);//将标定点与最后一个比它大的元素交换位置,这样标定点左边全是比它大的,右边全是比它小的。
        return r;
    }
};

  提交后的结果如下:

20220219

重刷

class Solution{
public:
    int findKthLargest(vector<int>& nums, int k){
       int l = 0;
       int r = nums.size()-1;
       while(true){
            int pivot = partition(nums, l, r);    
            if(pivot==k-1)
                return nums[pivot];
        
            else if(pivot<k-1)
                l = pivot + 1;
    
            else
                r = pivot - 1;    
       }
    }
    
    int partition(vector<int>& nums, int left, int right){
        int pivot = left; 
        int l = left + 1;
        int r = right;
        while(l<=r){
            if(nums[pivot] > nums[l] && nums[pivot] < nums[r]){
                swap(nums[l], nums[r]);
                l++;
                r--;
            }
            if(nums[pivot] <= nums[l])
                l++;
            if(nums[pivot] >= nums[r])
                r--;
        }
        swap(nums[r], nums[pivot]);
        return r;
    }
};

日积月累,与君共进,增增小结,未完待续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值