今天刷的题目思路非常清晰。
具体题目如下:
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;
}
};
日积月累,与君共进,增增小结,未完待续。