算法-TopK问题

数组中的第K个最大元素(经典题)

添加链接描述
思路:建一个大小为K的小根堆,那么最后的堆顶就是第K大的值

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int[]heap=new int[k];
        for (int i=0;i<nums.length;i++){
            if (i<k){
                heap[i]=nums[i];
                if (i==k-1){
                    // 建堆:从第一个非叶子节点到堆顶节点进行调整,调整完就是一个初始的小根堆
                    for (int j=k/2-1;j>=0;j--){
                        heapSort(heap,j);
                    }
                }
            }else {
               if (nums[i]>heap[0]){
                   //替换堆顶并重新调整
                   heap[0]=nums[i];
                   heapSort(heap, 0);
               }
            }
        }
        return heap[0];
    }

    private void heapSort(int[] heap, int j) {
        int k=j*2+1;
        while (k<heap.length){
            if (k+1<heap.length && heap[k+1]<heap[k]){
                k++;
            }
            if (heap[j]>heap[k]){
                swap(heap,k,j);
                j=k;
                k=j*2+1;
            }else {
                break;
            }
        }
    }

    private void swap(int[] heap, int k, int j) {
        int temp=heap[k];
        heap[k]=heap[j];
        heap[j]=temp;
    }
}

c++:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        int n=nums.size();
        vector<int>heap(k);
        for(int i=0;i<n;i++){
            if(i<k){
                heap[i]=nums[i];
                if(i==k-1){
                    for(int i=k/2-1;i>=0;i--){
                        heapSort(heap,i,k);
                    }
                }
            }else{
                if(nums[i]>heap[0]){
                    heap[0]=nums[i];
                    heapSort(heap,0,k);
                }
            }
        }
        return heap[0];
    }
    void heapSort(vector<int>& heap,int i,int k){
        int j=i*2+1;
        while(j<k){
            if(j+1<k && heap[j+1]<heap[j]){
                j++;
            }
            if(heap[i]>heap[j]){
                swap(heap[i],heap[j]);
                i=j;
                j=i*2+1;
            }else{
                break;
            }
        }
    }
};

前 K 个高频元素

前 K 个高频元素
方法和上题一模一样,只是多用一个hashMap记录出现的次数

class Solution {
    //<元素,元素出现的个数>
    Map<Integer , Integer> map = new HashMap<>();

    public int[] topKFrequent(int[] nums, int k) {
       
        for(int i : nums){
            map.put(i , map.getOrDefault(i,0) + 1);
        }
        
        //得到数组中的所有元素
        Iterator it = map.keySet().iterator();
        
        // 定义heap数组,下标从1开始
        int[] heap = new int[k+1];
        int i = 1;
        while(it.hasNext()){
            // 先初始化一个大小为k的堆,当堆中元素个数为k时,建立小根堆
            if( i <= k){
                heap[i] = (Integer)it.next();
                
                if(i == k){
                    for(int j = k/2 ; j >= 1 ; j--){
                        heapSort(heap,j);
                    }
                }
                i++;
            }else{   //小根堆建好后 ,对于每个新遍历的元素与堆顶比较,如果比堆顶大,替换堆顶,重新维持小根堆
                int key = (Integer)it.next();
                if(map.get(key) > map.get(heap[1])){
                   heap[1] = key;
                   heapSort(heap , 1);                
                } 
            }

        }
        
        // heap数组下标0没有使用,需要去掉
        int[] ans=new int[k];
        for(int j=1;j<=k;j++){
            ans[j-1]=heap[j];
        }
        return ans;
    }
    //维持小根堆
    //注意,堆中元素比较是比较它们出现的次数,即该元素在map中对应的value
    public void heapSort(int[] heap , int i){
        int j=i*2; // 0*2=0 所有下标要从1开始
        while (j<heap.length){                 // j+1比j小的话,就要把j+1换上去。
            if(j+1<heap.length && map.get(heap[j+1])<map.get(heap[j])){
                j++;
            }
            if(map.get(heap[i])>map.get(heap[j])){
                int temp = heap[i];
                heap[i]=heap[j];
                heap[j]=temp;
                i=j;
                j=j*2;
            }else {
                break;
            }
        }
    }
}

优先队列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值