题目
- 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
思路1:基于快排的partition思想(从大往小排)
- 选定一个数作为基点,将小于基点数点放在左边,大于等于基数的放在右边。
- 确定查找区域:如果左边的个数小于k,则说明第k大的数在基数右边区域。否则,则说明在左边区域。
- 在查找区域利用partition直接找到序号为k-1的数。
//返回基数在序列的位置
int partition(vector<int>&nums,int left,int right)
{
int key=nums[right];
for(int i=left;i<right;i++)
{
if(nums[i]<key)
swap(nums[left++],nums[i]);
swap(nums[right],nums[left]);
return left;
}
}
int findKthLargest(vector<int>& nums, int k) {
int len=nums.size(),order_k=len-k,pos,left=0,right=len-1;
while((pos=partition(nums,left,right))!=order_k)
{
pos<order_k ? left=pos+1 : right=pos-1;
}
return nums[order_k];
}
思路2:基于堆排序的思想。
- 用前k个数建立最小堆,然后从 k+1个数开始,与堆顶比较,如果大,就交换,直到结束。
void HeapAdjust(vector<int>& nums,int s,int length)//调整堆的程序
{
int temp=nums[s];
int child = 2*s+1;//这里因为下标从0开始,每个节点的子节点就是2s+1
while(child<length)
{
if(child+1<length && nums[child]>nums[child+1])
child++;
if(nums[s]>nums[child])
{
nums[s]=nums[child];
s=child;
child=2*s+1;
}
else
break;
nums[s]=temp;//这里的s已经是原来的child了
}
}
void BuildingHeap(vector<int>& nums,int k)//建立堆,从最后开始筛选
{
for(int i=(k-1)/2;i>=0;i--)
HeapAdjust(nums,i,k);
}
int findKthLargest(vector<int>& nums, int k)
{
int size=nums.size();
if(k>size) return nums[size-1];
vector<int> mynum;//(nums.begin(),nums.begin()+k);
int index=0;
for(;index<k;index++)
{
mynum.push_back(nums[index]);
}
int j=index;
for(int i=j;i<size;i++)
{
if(nums[i]>mynum[0])
{
swap(nums[i],mynum[0]);
HeapAdjust(mynum,0,index);
}
}
return mynum[0];
}