• LeetCode 347. 前K个高频元素


    题目描述

    给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

    哈希表 + 堆排

    先用哈希表进行频率统计,然后维护一个大小为k的小根堆,每次尝试往堆中插入一个元素。
    若堆的大小不足k,则直接插入。否则,与堆顶比较,若堆顶比当前元素大,直接舍弃当前元素(堆顶已经是k个中最小的了,当前元素更小,则当前元素不肯能是前k大);若堆顶比当前元素小,则用当前元素替换堆顶,并向下调整

    /**
    * 11ms
    **/
    class Solution {
        
        int[] heapVal;
        int[] heapFreq;
        int heapSize;
        int heapSizeLimit;
    
        public int[] topKFrequent(int[] nums, int k) {
            heapVal = new int[k];
            heapFreq = new int[k];
            heapSize = 0;
            heapSizeLimit = k;
            // 堆中下标0~k-1, 
            // 小根堆
            Map<Integer, Integer> freq = new HashMap<>();
            for (int i : nums) freq.put(i, freq.getOrDefault(i, 0) + 1);
            for (int key : freq.keySet()) insert(key, freq.get(key));
            return heapVal;
        }
    
        private void insert(int val, int freq) {
            if (heapSize == heapSizeLimit) {
                // 已经有k个元素在堆里了, 直接比较堆顶
                if (heapFreq[0] >= freq) return ; // 堆顶比当前元素大, 则当前元素无需插入
                // 堆顶比当前元素小, 则需要替换掉堆顶
                heapVal[0] = val;
                heapFreq[0] = freq;
                down(0);
                return ;
            }
            // 堆里不足k个元素, 则直接插入到末尾, 并向上调整
            heapVal[heapSize] = val;
            heapFreq[heapSize] = freq;
            up(heapSize);
            heapSize++;
        }
    
        private void up(int i) {
            while (i > 0 && heapFreq[(i - 1) / 2] > heapFreq[i]) {
                swap((i - 1) / 2, i);
                i = (i - 1) / 2;
            }
        }
    
        private void down(int i) {
            int min = i;
            if (2 * i + 1 < heapSize && heapFreq[2 * i + 1] < heapFreq[min]) min = 2 * i + 1;
            if (2 * i + 2 < heapSize && heapFreq[2 * i + 2] < heapFreq[min]) min = 2 * i + 2;
            if (min != i) {
                swap(min, i);
                down(min);
            }
        }
    
        private void swap(int i, int j) {
            int t = heapVal[i];
            heapVal[i] = heapVal[j];
            heapVal[j] = t;
    
            t = heapFreq[i];
            heapFreq[i] = heapFreq[j];
            heapFreq[j] = t;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    哈希表 + 快排

    同样先用哈希表进行频率统计。然后生成两个数组val[]freq[],分别存储值,以及值出现的频率。
    随后手写一个快排,按照freq[]从大到小排序。
    每趟排序,都会将数组分为左侧较大的,和右侧较小的两部分。
    每次查看左侧部分的长度leftLen

    • leftLen > k, 则只需要递归的对左侧部分进行处理。
    • leftLen = k, 直接结束。
    • leftLen < k, 则左侧一定是前k大, 随后对右侧进行处理, 并传入 k = k - leftLen
      随后取val[]的前k项, 作为答案返回即可
    class Solution {
        public int[] topKFrequent(int[] nums, int k) {
            Map<Integer, Integer> map = new HashMap<>();
            for (int i : nums) map.put(i, map.getOrDefault(i, 0) + 1);
            int n = map.size();
            int[] val = new int[n];
            int[] freq = new int[n];
            int i = 0;
            for (int key : map.keySet()) {
                val[i] = key;
                freq[i] = map.get(key);
                // System.out.printf("val[%d] = %d, freq[%d] = %d\n", i, val[i], i, freq[i]);
                i++;
            }
            quickSort(val, freq, 0, n - 1, k);
            int[] ret = new int[k];
            for (i = 0; i < k; i++) ret[i] = val[i];
            return ret;
        }
    
        // 按照freq从大到小排序
        private void quickSort(int[] val, int[] freq, int l, int r, int k) {
            if (l >= r) return ;
            int x = freq[l + r >> 1], i = l - 1, j = r + 1;
            while (i < j) {
                do i++; while (freq[i] > x);
                do j--; while (freq[j] < x);
                if (i < j) {
                    int t = freq[i];
                    freq[i] = freq[j];
                    freq[j] = t;
                    t = val[i];
                    val[i] = val[j];
                    val[j] = t;
                }
            }
            int left = j - l + 1;
            if (left == k) return ;
            if (left > k) quickSort(val, freq, l, j, k);
            if (left < k) quickSort(val, freq, j + 1, r, k - left);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
  • 相关阅读:
    基于PHP电影院选座售票系统设计与实现 开题报告
    【公司UI自动化学习】
    【JDBC】事务,批处理
    如何用Know Streaming来查询Kafka的消息
    齐岳定制:DBCO-PEG-Mesylate|二苯并环辛炔-聚乙二醇-甲磺酸酯
    图的遍历 广度优先遍历(爱思创)
    弹簧(压簧)力度计算与设计
    MySQL8.0索引新特性—支持降序索引与支持隐藏索引
    技术解读数据库如何实现“多租户”?
    linux部署Python项目,并解决依赖自定义模块报错问题
  • 原文地址:https://blog.csdn.net/vcj1009784814/article/details/126263561