力扣解题思路:347. 前 K 个高频元素

347. 前 K 个高频元素

思路:方法1:这道题最开始能想到的方法就是堆,因为是要输出前K个高频元素,我自然想到了大顶堆,堆中保存一个个2元数组,即数字和其出现的频率,按照其频率大小排序,用到了lambda表达式:

class Solution {//求前 k 大,用小根堆,求前 k 小,用大根堆。
    public int[] topKFrequent(int[] nums, int k) {
        PriorityQueue<int[]> queue = new PriorityQueue<int[]>((o1,o2)->(o2[1]-o1[1]));//这是大顶堆,复杂度是 nlogn
        Map<Integer,Integer> map = new HashMap<>();
        for(int i:nums){
            map.put(i,map.getOrDefault(i,0)+1);
        }
        for(int i:map.keySet()){
            queue.add(new int[]{i,map.get(i)});
        }
        int[] res = new int[k];
        for(int i=0;i<k;i++){
            res[i] = queue.poll()[0];
        }
        return res;
    }
}

方法2:但是这样的话,时间复杂度就刚好为O(nlogn),我能不能再让时间复杂度更小呢?由于只用输出前K个高频元素,那么我们的堆中是不是就可以只保存K个元素呢?自然就会想到小顶堆,因为小的元素再堆顶,直接poll出来即可,遍历所有的元素后,堆中自然就只有K个最大元素了:

class Solution {//求前 k 大,用小根堆,求前 k 小,用大根堆。
  public int[] topKFrequent(int[] nums, int k) {
      PriorityQueue<int[]> queue = new PriorityQueue<int[]>((o1,o2)->(o1[1]-o2[1]));//这是小顶堆,复杂度是 nlogK
      Map<Integer,Integer> map = new HashMap<>();
      for(int i:nums){
          map.put(i,map.getOrDefault(i,0)+1);
      }
      int n = 0;
      for(int i:map.keySet()){
          //if(n == k) queue.poll();
          queue.add(new int[]{i,map.get(i)});
          n++;
          if(n > k) queue.poll();
      }
      int[] res = new int[k];
      int p = 0;
      while(!queue.isEmpty()){
          res[p++] = queue.poll()[0];
      }
      return res;
  }
}

通过这两种方法,我们可以得出一个结论://求前 k 大,用小根堆,求前 k 小,用大根堆。
方法3:为了进一步降低时间复杂度,桶排序是个更好的选择(牺牲空间复杂度换取时间复杂度),第i个桶表示出现频率为i的元素,当然频率相同的元素可能并不只有一个,所以,每个桶中存放一个链表(因为链表是可变长度的),所有元素都存放在桶中后,我们就可以愉快的从后往前遍历啦,res数组填满K个元素即为我们的最终答案啦~~(●’◡’●)

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        ArrayList<Integer>[] buckets = new ArrayList[nums.length+1];
        Map<Integer,Integer> map = new HashMap<>();
        for(int i:nums){
            map.put(i,map.getOrDefault(i,0)+1);
        }
        for(int i:map.keySet()){
            if(buckets[map.get(i)] == null){
                buckets[map.get(i)] = new ArrayList<>();
            }
            buckets[map.get(i)].add(i);
        }
        int[] res = new int[k];
        int p = 0;
        for(int i = buckets.length-1;i>=0;i--){
            //if(p == k) return res;
            if(buckets[i] == null) continue;//初始化为null
            int size = buckets[i].size();
            while(size>0){
                res[p] = buckets[i].get(size-1);
                p++;
                if(p == k) return res;
                size--;
            }
        }
        return res;
        
    }
}

以上就是三种解法啦,涉及对堆以及桶排序的比较经典的题。注意题目中“数组中前 k 个高频元素的集合是唯一的。“因此 while(size>0)中无需有if(p == k) return res 的判断。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值