题目链接:数组中第K大元素
题目描述:
在未排序的数组中找到第 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
题目分析:TOP K问题,直接套堆模版即可
代码:
class Solution {
public int findKthLargest(int[] nums, int k) {
int n = nums.length;
int[] tree = new int[n+1];
for(int i = 1;i <= n;i++)
tree[i] = nums[i-1];
//建立一个大顶堆
for(int i = n/2;i >= 1;i--){
shiftdown(tree,i,n);
}
//做k-1次删除即可
while(k-->1){
swap(tree,1,n);
n--;
shiftdown(tree,1,n);
}
return tree[1];
}
public void swap(int[] tree,int x,int y){
int te = tree[x];tree[x] = tree[y];tree[y] = te;
}
//自上向下调整
public void shiftdown(int[] tree,int i,int n){
int pos = i;
boolean f = false;
while(!f&&i*2<=n){
if(tree[i]<tree[i*2]){//如果小于左子树
pos = i*2;
}else {
pos = i;
}
if(i*2+1<=n&&tree[pos]<tree[i*2+1]){//如果小于右子树
pos = i*2+1;
}
if(pos!=i){//交换,并继续向下调整
swap(tree,pos,i);
i = pos;
}else{//否则不调整退出循环
f = true;
}
}
}
}
上个思路是做k-1次删除,实质就是进行了一次堆排序,还有一种方法,我们维护一个前 k 个最大元素小顶堆,然后将数组元素不断插入,如果比堆顶元素小就跳过,如果大则替换堆顶元素,并重新调整,最后得到的堆顶元素即第k大的元素,只需将代码稍作调整即可
class Solution {
public int findKthLargest(int[] nums, int k) {
int n = k;
int[] tree = new int[n+1];
for(int i = 1;i <= n;i++)
tree[i] = nums[i-1];
//建立一个大小为k的小顶堆
for(int i = n/2;i >= 1;i--){
shiftdown(tree,i,n);
}
//维护一个前k个最大元素小顶堆
for(int i = k;i < nums.length;i++){
if(nums[i]>tree[1]){//大于堆顶则删除堆顶并重新调增
tree[1] = nums[i];
shiftdown(tree,1,n);
}
}
return tree[1];
}
public void swap(int[] tree,int x,int y){
int te = tree[x];tree[x] = tree[y];tree[y] = te;
}
//自上向下调整
public void shiftdown(int[] tree,int i,int n){
int pos = i;
boolean f = false;
while(!f&&i*2<=n){
if(tree[i]>tree[i*2]){//如果大于左子树
pos = i*2;
}else {
pos = i;
}
if(i*2+1<=n&&tree[pos]>tree[i*2+1]){//如果大于右子树
pos = i*2+1;
}
if(pos!=i){//交换,并继续向下调整
swap(tree,pos,i);
i = pos;
}else{//否则不调整退出循环
f = true;
}
}
}
}
还有快排的选择思路和基于快排改进的中位数算法,贴个链接吧,不写了
https://mp.weixin.qq.com/s/tYUcigO8b4y59Pg7v6imzw