力扣解题思路: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;
            int size = buckets[i].size();
            while(size>0){
     
                res[p] = buckets[i].get(size-1);
                p++;
                size--;
            }
        }
        return res;
        
    }
}

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

你可能感兴趣的:(力扣解题思路:347. 前 K 个高频元素)