topK问题解法

从arr[1,n]n个数中,找到最大的K个数。

1.排序 时间复杂度 n*lgn

2.局部排序

冒泡

每冒一次泡,找到一个最大值,直到k个。时间复杂度n*k。

只找到topk,不排序topk。

先用k个元素生成一个小顶堆,这个小顶堆用于存储当前最大的k个元素;

接着,从第k+1个元素开始扫描,和堆顶元素进行比较,如果被扫描的元素大于堆顶,则替换堆顶元素,并调整堆;

时间复杂度n*lgk

随机选择(减治)

时间复杂度 n

找到第k大的数,进行partition。

i = partition(arr, 1, n);

  • 如果i大于k,则说明arr[i]左边的元素都大于k,于是只递归arr[1, i-1]里第k大的元素即可;
  • 如果i小于k,则说明说明第k大的元素在arr[i]的右边,于是只递归arr[i+1, n]里第k-i大的元素即可

分治:快排,大问题分解为小问题,小问题要递归各个分支

减治:二分查找,随机选择。大问题分解为小问题,小问题只需要递归一个分支。

扩展:找出前K个出现频率最高的数

class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        // 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
        HashMap<Integer,Integer> map = new HashMap();
        for(int num : nums){
            if (map.containsKey(num)) {
               map.put(num, map.get(num) + 1);
             } else {
                map.put(num, 1);
             }
        }
        // 遍历map,用最小堆保存频率最大的k个元素
        PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer a, Integer b) {
                return map.get(a) - map.get(b);
            }
        });
        for (Integer key : map.keySet()) {
            if (pq.size() < k) {
                pq.add(key);
            } else if (map.get(key) > map.get(pq.peek())) {
                pq.remove();
                pq.add(key);
            }
        }
        // 取出最小堆中的元素
        List<Integer> res = new ArrayList<>();
        while (!pq.isEmpty()) {
            res.add(pq.remove());
        }
        return res;
    }

 

posted @ 2019-07-01 18:53  hhhl  阅读(611)  评论(0编辑  收藏  举报