【每日算法Day 82】面试经典题:求第K大数,我写了11种实现,不来看看吗?

简介: 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

题目链接


LeetCode 215. 数组中的第K个最大元素[1]

题目描述


在未排序的数组中找到第 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 ≤ 数组的长度。

题解


排序



image.png

小根堆+库函数



image.png

image.png

大根堆+库函数


c++ 自带 priority_queue, greater> ,可以实现大根堆。

python 没有大根堆实现。

image.png

小根堆+手写



image.png

大根堆+手写



image.png

image.png

快速选择



image.png

代码


排序(c++)

classSolution {
public:  
intfindKthLargest(vector<int>&nums, intk) {   
sort(nums.begin(), nums.end(), greater<int>()
            );     
returnnums[k-1]; 
    }
};

小根堆+STL优先队列(c++)

classSolution {
public:
intfindKthLargest(vector<int>&nums, intk) {  
priority_queue<int, vector<int>, greater<int>>Q;  
for (autox : nums) {   
Q.push(x);   
while (Q.size() >k) Q.pop(); 
        }    
returnQ.top(); 
    }
};

大根堆+STL优先队列(c++)

classSolution {
public:
intfindKthLargest(vector<int>&nums, intk) { 
priority_queue<int>Q;       
for (autox : nums) {     
Q.push(x);   
while (Q.size() >nums.size()-k+1) Q.pop();    
        }      
returnQ.top();  
    }
};

小根堆+手写(c++)

classSolution {
public: 
voidadjust(vector<int>&nums, intp, ints) {   
while (2*p+1<s) {  
intc1=2*p+1;   
intc2=2*p+2;    
intc= (c2<s&&nums[c2]<nums[c1]) ?c2 : c1;  
if (nums[c] <nums[p]) swap(nums[c], nums[p]); 
elsebreak;      
p=c;   
        }  
    }
intfindKthLargest(vector<int>&nums, intk) {   
intn=nums.size();     
for (inti=k/2-1; i>=0; --i) {    
adjust(nums, i, k);       
        }      
for (inti=k; i<n; ++i) {   
if (nums[0] >=nums[i]) continue;     
swap(nums[0], nums[i]);   
adjust(nums, 0, k);     
        }     
returnnums[0]; 
    }
};

大根堆+手写(c++)

classSolution {
public:  
voidadjust(vector<int>&nums, intp, ints) {   
while (2*p+1<s) {  
intc1=2*p+1;     
intc2=2*p+2;       
intc= (c2<s&&nums[c2]>nums[c1]) ?c2 : c1;    
if (nums[c] >nums[p]) swap(nums[c], nums[p]);  
elsebreak;  
p=c;      
        }   
    }
intfindKthLargest(vector<int>&nums, intk) { 
intn=nums.size();      
for (inti= (n-k+1)/2-1; i>=0; --i) {      
adjust(nums, i, (n-k+1));     
        }     
for (inti= (n-k+1); i<n; ++i) {    
if (nums[0] <=nums[i]) continue;     
swap(nums[0], nums[i]);     
adjust(nums, 0, (n-k+1));    
        }      
returnnums[0]; 
    }
};

快速选择(c++)

classSolution {
public:   
intpartition(vector<int>&nums, intl, intr) {   
intp=l+rand()%(r-l+1), m=l; 
swap(nums[p], nums[r]);
for (inti=l; i<r; ++i) {  
if (nums[i] <nums[r]) { 
swap(nums[i], nums[m++]);   
            }       
        }      
swap(nums[m], nums[r]);   
returnm;  
    }
intquickSelect(vector<int>&nums, intl, intr, intk) {  
if (l==r) returnnums[l];   
intm=partition(nums, l, r);    
if (k==m+1) returnnums[m];   
if (k<m+1) returnquickSelect(nums, l, m-1, k);   
returnquickSelect(nums, m+1, r, k);  
    }
intfindKthLargest(vector<int>&nums, intk) {  
intn=nums.size();       
srand((int)time(0));    
returnquickSelect(nums, 0, n-1, n-k+1);
    }
};

排序(python)

classSolution:  
deffindKthLargest(self, nums: List[int], k: int) ->int: 
nums.sort(reverse=True)  
returnnums[k-1]

小根堆+heapq(python)

classSolution:
deffindKthLargest(self, nums: List[int], k: int) ->int: 
returnheapq.nlargest(k, nums)[-1]

小根堆+手写(python)

classSolution:  
deffindKthLargest(self, nums: List[int], k: int) ->int:        defadjust(nums, p, s):       
while2*p+1<s:          
c1, c2=2*p+1, 2*p+2c=c2if (c2<sandnums[c2]<nums[c1]) elsec1ifnums[c] <nums[p]:      
nums[c], nums[p] =nums[p], nums[c]   
else:       
breakp=cn=len(nums)     
foriinrange(k//2-1, -1, -1):   
adjust(nums, i, k)      
foriinrange(k, n):  
ifnums[0] >=nums[i]: continuenums[0], nums[i] =nums[i], nums[0]  
adjust(nums, 0, k) 
returnnums[0]

大根堆+手写(python)

classSolution:  
deffindKthLargest(self, nums: List[int], k: int) ->int:   
defadjust(nums, p, s):    
while2*p+1<s:        
c1, c2=2*p+1, 2*p+2c=c2if (c2<sandnums[c2]>nums[c1]) elsec1ifnums[c] >nums[p]:     
nums[c], nums[p] =nums[p], nums[c]      
else:  
breakp=cn=len(nums)   
foriinrange((n-k+1)//2-1, -1, -1):   
adjust(nums, i, (n-k+1))   
foriinrange((n-k+1), n):  
ifnums[0] <=nums[i]: continuenums[0], nums[i] =nums[i], nums[0]  
adjust(nums, 0, (n-k+1))     
returnnums[0]

快速选择(python)

importrandomclassSolution: 
deffindKthLargest(self, nums: List[int], k: int) ->int:  
defpartition(nums, l, r): 
p, m=l+random.randint(0, r-l), lnums[p], nums[r] =nums[r], nums[p]        
foriinrange(l, r):         
ifnums[i] <nums[r]:     
nums[m], nums[i] =nums[i], nums[m]     
m+=1nums[m], nums[r] =nums[r], nums[m]    
returnmdefquickSelect(nums, l, r, k):    
ifl==r: returnnums[l]    
m=partition(nums, l, r)  
ifk==m+1: returnnums[m] 
ifk<m+1: returnquickSelect(nums, l, m-1, k)            
returnquickSelect(nums, m+1, r, k)           
n=len(nums)     
returnquickSelect(nums, 0, n-1, n-k+1)

参考资料

[1]

LeetCode 面试题 17.09. 第 k 个数: https://leetcode-cn.com/problems/kth-largest-element-in-an-array/

image.png

作者简介:godweiyang知乎同名华东师范大学计算机系硕士在读,方向自然语言处理与深度学习喜欢与人分享技术与知识,期待与你的进一步交流~

相关文章
|
12月前
|
算法 C++ Python
【每日算法Day 107】面试必考:良心推荐,一题三解,不看后悔一辈子
【每日算法Day 107】面试必考:良心推荐,一题三解,不看后悔一辈子
|
12月前
|
人工智能 算法
【每日算法Day 102】美团 AI 平台算法工程师面试编程题
【每日算法Day 102】美团 AI 平台算法工程师面试编程题
106 0
|
12月前
|
人工智能 算法
【每日算法Day 101】字节跳动 AI Lab 精选面试编程题
【每日算法Day 101】字节跳动 AI Lab 精选面试编程题
157 0
|
12月前
|
人工智能 算法
【每日算法Day 100】字节跳动 AI Lab 面试编程题(三道)
【每日算法Day 100】字节跳动 AI Lab 面试编程题(三道)
222 0
|
12月前
|
算法 C++ Python
【每日算法Day 86】面试经典题:把数字翻译成字符串
【每日算法Day 86】面试经典题:把数字翻译成字符串
|
12月前
|
存储 算法 C++
【每日算法Day 84】面试必考题:Trie(字典树/前缀树)的实现
【每日算法Day 84】面试必考题:Trie(字典树/前缀树)的实现
|
12月前
|
算法 C++ Python
【每日算法Day 82】面试经典题:求第K大数,我写了11种实现,不来看看吗?
【每日算法Day 82】面试经典题:求第K大数,我写了11种实现,不来看看吗?
|
12月前
|
存储 算法 C++
【每日算法Day 81】面试经典题:关于丑数,你真的理解为什么这么算吗?
【每日算法Day 81】面试经典题:关于丑数,你真的理解为什么这么算吗?
|
12月前
|
算法 C++
【每日算法Day 78】面试经典题:能说出全部四种方法,不录用你都不可能!
【每日算法Day 78】面试经典题:能说出全部四种方法,不录用你都不可能!
|
12月前
|
算法 C++
【每日算法Day 69】面试经典题:分发糖果问题
【每日算法Day 69】面试经典题:分发糖果问题