【堆】B003_前 K 个高频元素(排序 | PQ)

一、题目描述

Given a non-empty array of integers, return the k most frequent elements.

Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

二、题解

方法一:排序

使用排序算法对元素按照出现频率降序排列,最后取出前 k k 个元素。

/**
 * @date: 2/19/2020 5:09 PM
 * @Execution info:ms 击败 % 的j,MB 击败 % 的j
 */
public List<Integer> topKFrequent(int[] nums, int k) {

  HashMap<Integer, Integer> map = new HashMap<>();
  for (int num : nums) {
    map.put(num, map.getOrDefault(num, 0) + 1);
  }

  ArrayList<Integer> list = new ArrayList<>(map.keySet());
//    Collections.sort(list, new Comparator<Integer>() {
//      @Override
//      public int compare(Integer o1, Integer o2) {
//        return map.get(o2) - map.get(o1);
//      }
//    });
  Collections.sort(list, (e1, e2) -> map.get(e2).compareTo(map.get(e1)));

  LinkedList<Integer> resList = new LinkedList<>();
  for (int i = 0; i < k; i++) {
    resList.add(list.get(i));
  }
  return resList;
}

复杂度分析

  • 时间复杂度: O ( N l o g N ) O(N logN)
  • 空间复杂度: O ( N ) O(N)

方法二:最小堆

算法

  • 使用数组 / HashMap 统计元素的频率。
  • 维护一个元素数目为 k 的优先级队列(最小堆)。
  • 每次都将即将添加的元素与堆顶元素(堆中频率最小的元素)进行比较。
    • 如果比堆顶元素还小,直接扔掉;否则压入堆。
  • 最后,前 k 个高频元素就是堆中的 k 个元素。
/**
 * @thought:小根堆:维护堆大小不超过 k 即可。
 * 检查堆大小是否超过 k,如果超过,弹出堆顶。复杂度是 nlogk
 * @date: 2/19/2020 5:09 PM
 * @Execution info:16ms 击败 % 的j,MB 击败 5.47% 的j
 * @Asymptotic Time Complexity:O()
 */
public List<Integer> topKFrequent1(int[] nums, int k) {

  LinkedList<Integer> resList = new LinkedList<>();
  HashMap<Integer, Integer> map = new HashMap<>();
  for (int num : nums) {
    map.put(num, map.getOrDefault(num, 0) + 1);
  }

  //lambda形式的自定义比较器
  PriorityQueue<Integer> pQ = new PriorityQueue<>(
          (e1, e2) -> map.get(e1) - map.get(e2)
  );

  for (Integer key : map.keySet()) {
    if (pQ.size() < k) {
      pQ.add(key);
    } else if (map.get(pQ.peek()) < map.get(key)){
      pQ.poll();
      pQ.add(key);
    }
  }
  while (!pQ.isEmpty()) {
    resList.add(pQ.poll());
  }
  return resList;
}

复杂度分析

  • 时间复杂度: O ( N   l o g k ) O(N\ logk) ,map 建立映射需要 O ( N ) O(N) 时间;建堆需要 O ( N l o g ( k ) ) O(Nlog(k)) 。 因此总复杂度为 O ( N + N log ( k ) ) O(N + N \log(k)) = O ( N l o g ( k ) ) O(Nlog(k))
    • 因为始终存在一个正常数 M M ,使得 N ( 1 + l o g K ) < M N l o g K N(1+logK)<M*NlogK .
  • 空间复杂度: O ( N ) O(N) ,存储映射需要的存储空间。
发布了419 篇原创文章 · 获赞 94 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/104402760