念两句诗

千古斜阳,无处问长安。
【宋代】张舜民《江神子·癸亥陈和叔会于赏心亭》
随笔 - 12,  文章 - 1,  评论 - 0,  阅读 - 2446

1.题目描述

   

 

2.过程

主要分享小根堆的构建和调整过程,解题逻辑
  1.在原数组的基础上建立一个大小为k的小根堆;

  2.顺序遍历数组,遇到大于堆顶的元素,替换堆顶元素并向下调整堆;

  3.最终返回堆顶元素nums[0], 即为第k大元素。

建堆和调整函数可以复用,可以改为大根堆,删除k-1个元素,堆顶即为题解

3.小顶堆代码

复制代码
 1 class Solution {
 2 public:
 3     int findKthLargest(vector<int>& nums, int k) {
 4         buildheap(nums,k);              //小根堆,大小为k,存储最大的k个元素
 5         for(int i=k;i<nums.size();i++){
 6             cout<<nums[0]<<endl;
 7             if(nums[i]>nums[0]){
 8                 swap(nums[0],nums[i]);  //更换堆顶元素
 9                 downadjust(nums,k);     //下降调整堆
10             }
11         }
12         cout<<endl;
13         return nums[0];
14     }
15 
16     void buildheap(vector<int> &nums,int k){        //建小顶堆
17         for(int i=1;i<=k;i++){                      //插入k个元素到堆中,第1~K个元素
18             int n=i;
19             while(n!=1 &&nums[n-1]<nums[n/2-1]){  //第n个元素的下标是i-1(为了整齐,i的左儿子是2i,右儿子是2i+1)
20                 swap(nums[n-1],nums[n/2-1]);      //根节点如果是0,则要用2i+1和2i+2 代表左右儿子
21                 n=n/2;
22             }
23         }
24     }
25     void downadjust(vector<int>&nums,int k){//删除堆顶元素,插入新的元素,两个步骤合成为一个函数更简单
26         int i=1;                        //第一个元素,对应nums[0]
27         while(true){                    //删除堆顶和插入部分在主函数,这里直接下降调整堆顶元素
28             if(2*i>k){                  //第i个元素的左儿子不存在
29                 break;
30             }else if(2*i==k){           //只有一个左儿子,
31                 if(nums[i-1]>nums[2*i-1]){
32                     swap(nums[i-1],nums[2*i-1]);
33                 }
34                 break;
35             }else{                      //两个儿子都在
36                 int f=nums[2*i-1]<nums[2*i] ? 0 : 1;
37                 if(nums[2*i-1+f]<nums[i-1]){
38                     swap(nums[i-1],nums[2*i-1+f]);
39                     i=2*i+f;
40                 }else{
41                     break;
42                 }
43             }
44         }            
45     }  
46 };
复制代码

 4.大顶堆实现

复制代码
 1 class Solution {
 2 public:
 3     int findKthLargest(vector<int>& nums, int k) {
 4         int n=nums.size();
 5         buildheap(nums,n);              //大根堆,大小为nums.size()
 6         for(int i=1;i<k;i++){           //删除k-1个元素
 7             swap(nums[0],nums[n-i]);  //更换堆顶,堆尾元素,相当于删除堆顶
 8             downadjust(nums,n-i);     //下降调整堆,size--
 9         }
10         return nums[0];
11     }
12 
13     void buildheap(vector<int> &nums,int k){        //建大顶堆
14         for(int i=1;i<=k;i++){                      //插入k个元素到堆中,第1~K个元素
15             int n=i;
16             while(n!=1 &&nums[n-1]>nums[n/2-1]){  //第n个元素的下标是i-1(为了整齐,i的左儿子是2i,右儿子是2i+1)
17                 swap(nums[n-1],nums[n/2-1]);      //根节点如果是0,则要用2i+1和2i+2 代表左右儿子
18                 n=n/2;
19             }
20         }
21     }
22     void downadjust(vector<int>&nums,int k){//删除堆顶:堆顶和堆尾元素交换,直接下降调整堆顶元素
23         int i=1;                        //第一个元素,对应nums[0]
24         while(true){                    
25             if(2*i>k){                  //第i个元素的左儿子不存在,说明到底了
26                 break;
27             }else if(2*i==k){           //只有一个左儿子,
28                 if(nums[i-1]<nums[2*i-1]){
29                     swap(nums[i-1],nums[2*i-1]);
30                 }
31                 break;
32             }else{                      //两个儿子都在,选一个大的交换
33                 int f=nums[2*i-1]>nums[2*i] ? 0 : 1;
34                 if(nums[2*i-1+f]>nums[i-1]){
35                     swap(nums[i-1],nums[2*i-1+f]);
36                     i=2*i+f;
37                 }else{
38                     break;
39                 }
40             }
41         }            
42     }  
43 };
44 /*
45 1.删除堆顶 :堆顶和堆尾元素交换,然后从堆顶 下降调整,堆大小-1;
46 2.插入元素 :插入元素放到堆尾,堆大小+1,向上调整堆即可;
47 */
48 
49 作者:xi-jiu
50 链接:https://leetcode.cn/problems/kth-largest-element-in-an-array/solution/-by-xi-jiu-9dtr/
51 来源:力扣(LeetCode)
52 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复制代码

 5.快速选择

快速选择:每次选择一个关键字(通常范围内第一个),利用快排的思想找到它在有序数组中的位置index,比较和k的大小进一步缩小查找范围,
快排一次后:左侧的数字都比关键字小,右侧都比关键字大;

复制代码
 1 //快排的思想,降序
 2 class Solution {
 3 public:
 4     int findKthLargest(vector<int>& nums, int k) {
 5         int l=0,r=nums.size()-1;
 6         swap(nums[0],nums[nums.size()/2]);  //防止有序测例,退化为线性
 7         while(l<r){
 8             int mid =partition(nums,l,r);
 9             if(mid==k-1){               //找到第k大的数
10                 return nums[mid];
11             }else if(mid>=k){
12                 r=mid-1;
13             }else{
14                 l=mid+1;
15             }
16         }
17         return nums[l];
18     }
19     int partition(vector<int> &nums,int l,int r){    //降序快排
20         int pivot=l;
21         while(l<r){
22             while(l<r && nums[r] < nums[pivot] ) r--;           //右侧的数只能小于 支点
23             while(l<r && nums[l] >= nums[pivot] ) l++;          //左侧的数可以大于等于
24             swap(nums[l],nums[r]);
25         }
26         swap(nums[pivot],nums[l]);   
27         return l;
28     }
29 };
复制代码

 

posted on   昔九  阅读(208)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示