您的位置:首页 > 职场人生

【算法】O(1)空间,不改变原数组的情况下找第K大的数

2017-04-15 16:35 225 查看
找到无序数组中第K大的数,这道题蜜汁经典,腾讯和头条的面试中都被问到了,我一般用的都是大小为K的小顶堆和快排扫一半这两种思路做这道题,直到前几天面试头条的时候,终面面试官问,有没有O(1)空间【严格的O(1)空间,即不能用递归】且不改变原数组的情况下,找第K大的数。当场没有想起来,下来之后突然就想到了。所以特此来总结一下。

找数组第K大的数 ,Leetcode上有一道原题:

215. Kth Largest Element in an Array

常规的两种方法——小顶堆和快排分治

快排扫一半

就是快排每次扫完之后,看轴值得位置在哪里,如果大于k则扫前一半,小于k则扫后一半,如果等于k则说明找到了【PS,这里的k是指从0开始数的第K大的数】

这种方法的时间复杂度,平均意义上是O(n)

int findKsort(vector<int>& nums,int k,int left,int right){
if(left==right)                //其实这一步也可以不加的,因为下面有判断出如果相等的话,就直接返回了
return nums[left];
int i = left;
int j = right;
int q = nums[j];
while(i<j){
while(i<j && nums[i]>q) i++;
nums[j] = nums[i];
while(i<j && nums[j]<=q) j--;
nums[i] = nums[j];
}
nums[i] = q;
if(i == k)
return nums[i];
if(i>k)
return findKsort(nums,k,left,i-1);      //顺便要注意这个地方是i-1和i+1,不能是i否则会死循环。
else
return findKsort(nums,k,i+1,right);
}
int findKthLargest(vector<int>& nums, int k) {
return findKsort(nums,k-1,0,nums.size()-1);
}


K大小的小顶堆

这种方法就是,先把数组中前K个数建立一个小顶堆,然后再依次往后扫,如果小于堆顶元素则继续往后扫,如果大于堆顶元素,则把堆顶元素pop出,然后再push进这个元素。

这种算法的复杂度是O(nlogK)

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


O(1)空间,不改变原数组的做法

这其实也是一个二分法啦,只不过之前的二分法都是从数组索引的角度去二分,而这次等于是二分一个数是否是满足第K大数的条件。 【即相当二分法求一个单调函数值f(x)−k=0,依次去二分x看这个函数什么时候相等。】

这种方法的复杂度是需要讨论的,如果数组中全都是int类型的整数,那么时间复杂度是O(n)

因为本质上查找一遍数组需要O(n),而至多需要查找log(Max−Min)≤32所以至多查找32遍,所以复杂度还是O(n)的

PS,这种方法其实还是只是适用于整数,因为如果是浮点数的话,其复杂度是不可估计的。

int findKthLargest(vector<int>& nums, int k) {
int left = INT_MAX;
int right = INT_MIN;
for(auto x:nums){
left = min(x,left);
right = max(x,right);
}
while(left<=right){
int mid = left + (right-left)/2;
int count1 = 0;
int count2 = 0;
for(auto x:nums){
if(x>=mid)
count1++;
if(x>mid)
count2++;
}
if(count1 >=k && count2 <k)
return mid;
if(count1 <k)
right = mid-1;
else
left = mid+1;
}
return -1;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐