[每日一题][找工作第78天][2025-12-09] Leetcode 347. 前 K 个高频元素

题目

347. 前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
 
示例 1:
输入:nums = [1,1,1,2,2,3], k = 2
输出:[1,2]
示例 2:
输入:nums = [1], k = 1
输出:[1]
示例 3:
输入:nums = [1,2,1,2,1,2,3,1,3,2], k = 2
输出:[1,2]
 
提示:

  • 1 <= nums.length <= 105
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
     
    进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。

我的代码(Python)

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
var topKFrequent = function(nums, k) {
    let cntMap = new Map();
    for (let num of nums) {
        if (cntMap.has(num)) {
            cntMap.set(num, cntMap.get(num) + 1);
        } else {
            cntMap.set(num, 1);
        }
    }
    // console.log(cntMap);
    class HeapNode {
        constructor(cnt, val) {
            this.cnt = cnt;
            this.val = val;
        }
    }
    class MyKMinHeap {
        constructor(k) {
            this.maxCnt = k;
            this.numList = [];
        }

        bubbleUp() {
            let idx = this.numList.length - 1;
            let parentIdx = Math.floor((idx - 1) / 2);
            while (parentIdx < idx && parentIdx >= 0 &&this.numList[idx].cnt < this.numList[parentIdx].cnt) {
                let tmp = this.numList[idx];
                this.numList[idx] = this.numList[parentIdx];
                this.numList[parentIdx] = tmp;
                idx = parentIdx;
                parentIdx = Math.floor((idx - 1) / 2);
            }
        }

        sink() {
            let idx = 0;
            let lChild = idx * 2 + 1;
            let rChild = idx * 2 + 2;
            // console.log("numList: " + this.numList);
            // console.log(lChild);
            // console.log(this.numList[lChild]);
            // console.log(rChild);
            // console.log(this.numList[rChild]);
            while ((lChild < this.numList.length && this.numList[idx].cnt > this.numList[lChild].cnt) || (rChild < this.numList.length && this.numList[idx].cnt > this.numList[rChild].cnt)) {
                let toBeChanged = lChild;
                if (lChild < this.numList.length && rChild < this.numList.length) {
                    if (this.numList[lChild].cnt > this.numList[rChild].cnt) {
                        toBeChanged = rChild;
                    }
                }
                let tmp = this.numList[toBeChanged];
                this.numList[toBeChanged] = this.numList[idx];
                this.numList[idx] = tmp;
                idx = toBeChanged;
                lChild = idx * 2 + 1;
                rChild = idx * 2 + 2;
                // console.log('idx: ' + idx + ", lChild: " + lChild + ", rChile: " + rChild);
            }
        }

        insert(cnt, val) {
            // console.log('cnt: ' + cnt + ", val: " + val);
            if (this.numList.length == k) {
                if (cnt <= this.numList[0].cnt) {
                    return false;
                }
                this.extractMin();
            }
            this.numList.push(new HeapNode(cnt, val));
            this.bubbleUp();
            return true;
        }

        extractMin() {
            this.numList[0] = this.numList[this.numList.length - 1];
            this.numList.pop();
            this.sink();
        }
    }
    let myHeap = new MyKMinHeap(k);
    cntMap.forEach((value, key) => {
        myHeap.insert(value, key);
        // console.log(myHeap.numList);
    });
    let result = [];
    for (let heapNode of myHeap.numList) {
        result.push(heapNode.val);
    }
    return result;
};

点评

经过上一题目的洗礼,215. 数组中的第K个最大元素我的解法这里最终还是实现了一个最小堆来处理。
不过理论上这个时间复杂度仍然是O(nlogn)才对……
官方的第一个方法也是如此。
第二个解法的方向当时我想了一下,没深入,因为觉得时间复杂度不会变,所以回来实现堆来解题,看来还是直观印象不正确。


baddif@gmail.com

AI简历优化站

Nonpareil.me:优化简历,助力职场
开源代码

AI求职跟踪器(建设中)

开源代码

主站(建设中)

Nonpareil Me

相关平台

Github Issues / Notion / Blog

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部