Leetcode(347)——前 K 个高频元素

LeetCode刷题日记之前K个高频元素 前K个高频元素,这是一个很有代表性的问题,在实际生活中的应用场景其实也很多,比如微博里每天统计实时热点信息等。 先看下题: 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] 进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。 这道题的进阶要求时间复杂度要优于O(nlogn),那一般的快排,归并等就可以抛弃 阅读详情

Leetcode(347)——前 K 个高频元素

题目

题解

方法一:桶排序

思路

​​  顾名思义,桶排序的意思是为每个值设立一个桶,桶内记录这个值出现的次数(或其它属性),然后对桶进行排序。针对样例来说,我们先通过桶排序得到三个桶 [1,2,3,4],它们的值分别为 [4,2,1,1],表示每个数字出现的次数。
​​  紧接着,我们对桶的频次进行排序,前 k 大个桶即是前 k 个频繁的数。这里我们可以使用各种排序算法,甚至可以再进行一次桶排序,把每个旧桶根据频次放在不同的新桶内。针对样例来说,因为目前最大的频次是 4,我们建立 [1,2,3,4] 四个新桶,它们分别放入的旧桶为 [[3,4],[2],[],[1]],表示不同数字出现的频率。最后,我们从后往前遍历,直到找到 k 个旧桶。

代码实现

我的:

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        if(nums.size() == 1) return nums;
        unordered_map<int, int> times;
        int maxcount = 0;
        for(auto& it: nums) maxcount = max(maxcount, ++times[it]);
        
        vector<vector<int>> bucket(maxcount+1);
        for(auto& it: times) bucket[it.second].push_back(it.first);
        
        vector<int> ans;
        // 因为保证答案唯一,所以不考虑 maxcount 的大小
        while(k > 0){
            if(!bucket[maxcount].empty()){
                k -= bucket[maxcount].size();
                ans.insert(ans.end(), bucket[maxcount].begin(), bucket[maxcount].end());
            }
            maxcount--;
        }
        return ans;
    }
};
复杂度分析

时间复杂度:O(n)O(n)O(n),其中 nnn 是数组长度
空间复杂度:O(max(n,k))O(max(n, k))O(max(n,k)),其中 nnn 是数组长度

方法二:堆排序

思路

​​  首先遍历整个数组,并使用哈希表记录每个数字出现的次数,并形成一个「出现次数数组」。找出原数组的前 kkk 个高频元素,就相当于找出「出现次数数组」的前 kkk 大的值。

​​  最简单的做法是给「出现次数数组」排序。但由于可能有 O(N)O(N)O(N) 个不同的出现次数(其中 NNN 为原数组长度),故总的算法复杂度会达到 O(Nlog⁡N)O(N\log N)O(NlogN),不满足题目的要求。

在这里,我们可以利用堆的思想:建立一个小顶堆,然后遍历「出现次数数组」:

  • 如果堆的元素个数小于 kkk,就可以直接插入堆中。
  • 如果堆的元素个数等于 kkk,则检查堆顶与当前出现次数的大小。如果堆顶更大,说明至少有 kkk 个数字的出现次数比当前值大,故舍弃当前值;否则,就弹出堆顶,并将当前值插入堆中。

​​  遍历完成后,堆中的元素就代表了「出现次数数组」中前 kkk 大的值。

代码实现

Leetcode 官方题解:

class Solution {
public:
    static bool cmp(pair<int, int>& m, pair<int, int>& n) {
        return m.second > n.second;
    }

    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> occurrences;
        for (auto& v : nums) {
            occurrences[v]++;
        }

        // pair 的第一个元素代表数组的值,第二个元素代表了该值出现的次数
        priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp)> q(cmp);
        for (auto& [num, count] : occurrences) {
            if (q.size() == k) {
                if (q.top().second < count) {
                    q.pop();
                    q.emplace(num, count);
                }
            } else {
                q.emplace(num, count);
            }
        }
        vector<int> ret;
        while (!q.empty()) {
            ret.emplace_back(q.top().first);
            q.pop();
        }
        return ret;
    }
};
复杂度分析

时间复杂度:O(Nlog⁡k)O(N\log k)O(Nlogk),其中 NNN 为数组的长度。我们首先遍历原数组,并使用哈希表记录出现次数,每个元素需要 O(1)O(1)O(1) 的时间,共需 O(N)O(N)O(N) 的时间。随后,我们遍历「出现次数数组」,由于堆的大小至多为 kkk,因此每次堆操作需要 O(log⁡k)O(\log k)O(logk) 的时间,共需 O(Nlog⁡k)O(N\log k)O(Nlogk) 的时间。二者之和为 O(Nlog⁡k)O(N\log k)O(Nlogk)。
空间复杂度:O(N)O(N)O(N)。哈希表的大小为 O(N)O(N)O(N),而堆的大小为 O(k)O(k)O(k),共计为 O(N)O(N)O(N)。

方法三:(改进的)快速排序——即快速选择排序

思路

​​  我们可以使用快速选择算法,求出「出现次数数组」的前 kkk 大的值。

​​  首先我们使用 arr\textit{arr}arr 数组存储每个数字对应的出现次数,然后遍历数组获取出现次数。然后对 arr\textit{arr}arr 数组进行快速排序。

​​  在对数组 arr[l…r]\textit{arr}[l \ldots r]arr[l…r] 做快速排序的过程中,我们首先将数组划分为两个部分 arr[i…q−1]\textit{arr}[i \ldots q-1]arr[i…q−1] 与 arr[q+1…j]\textit{arr}[q+1 \ldots j]arr[q+1…j],并使得 arr[i…q−1]\textit{arr}[i \ldots q-1]arr[i…q−1] 中的每一个值都不超过 arr[q]\textit{arr}[q]arr[q],且 arr[q+1…j]\textit{arr}[q+1 \ldots j]arr[q+1…j] 中的每一个值都大于 arr[q]\textit{arr}[q]arr[q]。

于是,我们根据 kkk 与左侧子数组 arr[i…q−1]\textit{arr}[i \ldots q-1]arr[i…q−1] 的长度(为 q−iqq-iqq−iq)的大小关系:

  • 如果 k≤q−ik \le q-ik≤q−i,则数组 arr[l…r]\textit{arr}[l \ldots r]arr[l…r] 前 kkk 大的值,就等于子数组 arr[i…q−1]\textit{arr}[i \ldots q-1]arr[i…q−1] 前 kkk 大的值。
  • 否则,数组 arr[l…r]\textit{arr}[l \ldots r]arr[l…r] 前 kkk 大的值,就等于左侧子数组全部元素,加上右侧子数组 arr[q+1…j]\textit{arr}[q+1 \ldots j]arr[q+1…j] 中前 k−(q−i)k - (q - i)k−(q−i) 大的值。

​​  原版的快速排序算法的平均时间复杂度为 O(Nlog⁡N)O(N\log N)O(NlogN)。我们的算法中,每次只需在其中的一个分支递归即可,因此算法的平均时间复杂度降为 O(N)O(N)O(N)。

代码实现

Leetcode 官方题解:

class Solution {
public:
    void qsort(vector<pair<int, int>>& v, int start, int end, vector<int>& ret, int k) {
        int picked = rand() % (end - start + 1) + start;
        swap(v[picked], v[start]);

        int pivot = v[start].second;
        int index = start;
        for (int i = start + 1; i <= end; i++) {
            if (v[i].second >= pivot) {
                swap(v[index + 1], v[i]);
                index++;
            }
        }
        swap(v[start], v[index]);

        if (k <= index - start) {
            qsort(v, start, index - 1, ret, k);
        } else {
            for (int i = start; i <= index; i++) {
                ret.push_back(v[i].first);
            }
            if (k > index - start + 1) {
                qsort(v, index + 1, end, ret, k - (index - start + 1));
            }
        }
    }

    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> occurrences;
        for (auto& v: nums) {
            occurrences[v]++;
        }

        vector<pair<int, int>> values;
        for (auto& kv: occurrences) {
            values.push_back(kv);
        }
        vector<int> ret;
        qsort(values, 0, values.size() - 1, ret, k);
        return ret;
    }
};
复杂度分析

时间复杂度:
​​  其中 NNN 为数组的长度。设处理长度为 NNN 的数组的时间复杂度为 f(N)f(N)f(N)。由于处理的过程包括一次遍历和一次子分支的递归,最好情况下,有 f(N)=O(N)+f(N/2)f(N) = O(N) + f(N/2)f(N)=O(N)+f(N/2),根据主定理,能够得到 f(N)=O(N)f(N) = O(N)f(N)=O(N)。
​​  最坏情况下,每次取的枢轴都位于数组的两端,时间复杂度退化为 O(N2)O(N^2)O(N2)。但由于我们在每次递归的开始会先随机选取中枢元素,故出现最坏情况的概率很低。
​​  平均情况下,时间复杂度为 O(N)O(N)O(N)。

空间复杂度:O(N)O(N)O(N)。其中哈希表的大小为 O(N)O(N)O(N),用于排序的辅助数组的大小也为 O(N)O(N)O(N),快速排序的空间复杂度最好情况为 O(log⁡N)O(\log N)O(logN),最坏情况为 O(N)O(N)O(N)

Leetcode- 347( 桶排序 或 快排思想) 题目链接 LeetCode-347 题目描述 给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 示例 1: 输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] 思路一 根据自己的做法,使用一个列为2的二维数组来存储 <元素, 个数>。 根据二维数组的第二列**(元素个数), 利用快速排序对二维数组进行排序。 取出二维数组中前 k 个**的 元素... 阅读详情

相关推荐

LeetCode-347-前k个高频元素-中等(红黑树/堆/快排)

一 题目 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 二 前言 像这种topK问题(前k小/前k大/第k大/第k小)的题解都是套路,基本就是堆排序O(nlogk)、快速选择O(n)【最快】、二叉搜索树O(nlogk)。本题只是在这基础上的变形而已,要处理值和频率对应的问题,所以考虑以哈希表为底层的unordered_map来处理,然后在后面排序的过程中需要注意数据结构的变化。 三 题解 1.两个红黑树反着赋值。 思路:考虑到

哼 1532

前K个高频元素

给定一个非空的整数数组,返回其中出现频率前 k 高的元素,示例如下: 本题涉及三个内容: 1.对数组元素出现的频率进行统计; 2.对频率进行排序; 3.找出前k个高频的元素。 解决方法: 1.实现频率统计可以使用map; 2.实现频率排序可以使用优先级队列实现。 优先级队列是披着队列外衣的堆,因为优先级队列对外接口只能是从头取元素和从队尾添加元素,优先级队列的内部元素自动按照权值进行排列,缺省情况下priority_queue利用max-heap(大顶堆)完成对元素的排序,这个大顶堆是以

qq_43697646的博客 990

华为OD机试真题 - 矩阵匹配 牛客网

2024华为OD机试真题,代码包含语言java、js、python、c 代码基本都有详细注释。 题目描述 从一个 N * M(N ≤ M)的矩阵中选出 N 个数,任意两个数字不能在同一行或同一列,求选出来的 N 个数中第 K 大的数字的最小值是多少。 输入描述 输入矩阵要求:1 ≤ K ≤ N ≤ M ≤ 150 输入格式: N M K N*M矩阵 输出描述 N*M 的矩阵中可以选出 M! / N! 种组合数组,每个组合数组种第 K 大的数中的最小值。无需考虑重复数字,直接取字典排序结果即可。

2301_76543445的博客 497

leetcode:347. 前 K 个高频元素

题目来源 leetcode 题目描述 题目解析 对于这类统计数字的问题,首先应该考虑用hashmap来做,建立数字和其出现的映射,然后再按照出现次数进行排序,可以用堆排序做,在 C++ 中使用 priority_queue 来实现,默认是最大堆 class Solution { public: vector<int> topKFrequent(vector<int>& nums, int k) { std::unordered_map<in

OceanStar的博客 535

《涨知识啦29》-DBR的工作原理及其在VCSEL中的作用

分布式布拉格(Distributed Bragg Reflection,简称DBR)反射镜是垂直腔面发射激光器(Vertical-Cavity Surface-Emitting Laser,简称VCSEL)的重要组成部分。典型的DBR反射镜是由1/4ni波长厚度的高折射率和低折射率材料交替组成(ni是该层的折射率)。其反射率取决于组成对数、边界条件以及折射率差。 图1 布拉格反射镜的工作原理 DBR反射镜的工作原理如图1所示。根据反射原理,当光从光疏介质n1射向光密介质n2(折射率n2>n1)时,反

simucal的博客 7981

王爽《汇编语言》课程设计2(不涉及软盘版本)

assume cs:code,ds:data,ss:stack stack segment db 128 dup (0) stack ends data segment db 256 dup (0) data ends code segment start: mov ax,stack mov ss,ax mov sp,128 ...

weixin_41944412的博客 1178

【中等】力扣算法题解析LeetCode347:前 K 个高频元素

LeetCode 347题「前K个高频元素」的解题思路与Java实现。题目要求在整数数组中找到出现频率最高的前k个元素,需满足时间复杂度优于O(n log n)。核心解法分三步:首先用哈希表统计元素频率,然后通过最小堆维护前k高频元素,最后输出结果。该方法时间复杂度为O(n log k),空间复杂度O(n)。

ylumwd的博客 1420

Nvidia Isaac Sim图形界面 入门教程 2024(3)

在使用Isaac Sim时,最先接触到的应该是它的图形界面,此处将简单介绍图形界面中常用的一些组件:Isaac Sim的界面的常用内容可以分为几个板块。

m0_56661101的博客 4545

力扣347:前k个高频元素---leetcode347:Top K Frequent Elements

力扣347:前k个高频元素---leetcode347:Top K Frequent Elements 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

xxxnnn1991的博客 393

三相直流无刷电机(带HALL传感器)BLDC控制一

本案例选择TIM0的CH0/CH1/CH2三个通道接入三路原始hall输出信号。三路TIM_CHx(48)通过配置存入到NIP寄存器(new input pattern,3 bits)内。未完待续。

m0_69929716的博客 405

把 SM30 用顺:从表设计到权限与传输,全面掌握 SAP Table Maintenance Generator

摘要 SAP的Table Maintenance Generator(TMG)是为配置表维护需求设计的经典工具,能够生成标准化的维护对话框(SM30)。它支持单表、维护视图(多表关联)和视图簇(导航式维护)三种维护对象类型。使用TMG前需注意三个关键设置:1)表维护权限选项;2)交付类(决定数据传输行为);3)客户端字段配置。通过SE54/SE11生成维护对话框时,需选择维护类型(一步/两步)和记录例程(控制传输)。TMG生成的对象包含函数组、屏幕和处理模块,但部分标准框架不可修改。实际应用中,可通过参数事

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 176

Leetcode 347. 前 K 个高频元素

Leetcode 347. 前 K 个高频元素1、问题分析2、问题解决3、总结 1、问题分析 题目链接:https://leetcode-cn.com/problems/top-k-frequent-elements/   本质上就是一个 map使用的问题。代码我已经进行了详细的注释,理解应该没有问题,读者可以作为参考,如果看不懂(可以多看几遍),欢迎留言哦!我看到会解答一下。 2、问题解决   笔者以C++方式解决。 #include "iostream" using namespace std;

珍惜 9212

【Bug已解决】This model‘s maximum context length is X tokens. However, you requested Y tokens 解决方案

summary_prompt = "请将以下对话历史压缩成一段简洁摘要,保留关键决策和结论:\n" + format_messages(old_part)return [{"role": "system", "content": f"此前对话摘要:{summary}"}] + recent_part这种方式能在大幅降低 token 消耗的同时,尽量保留任务推进所需的关键上下文,是目前业内做长会话 Agent 最常见的处理方式之一。方案适用场景推荐指数滑动窗口裁剪短任务,对早期历史依赖不强⭐⭐⭐。

一键难忘的博客 1万+

LeetCode刷题——347. 前 K 个高频元素

✊✊✊🌈大家好!本篇文章将较详细介绍栈的题目347.前 K 个高频元素,主要记录小顶堆的使用方式,代码语言为:C++代码😇。

君莫笑lucky的博客 845

基于YOLO26深度学习框架的文档表格识别系统的算法研究实现方法

本文研究了基于YOLO26深度学习框架的文档表格识别系统实现方法。系统采用YOLO26网络架构,通过数据预处理、模型训练、检测推理和表格分析四个模块实现高效表格识别。研究详细阐述了数据归一化、增强等技术处理,以及采用迁移学习策略优化模型训练过程。实验表明,该系统能有效识别多种表格结构并生成结构化数据,为文档自动化处理提供了可靠解决方案。

一键难忘的博客 969

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

LeetCode347. 前 K 个高频元素

LeetCode347. 前 K 个高频元素

Love Peace 1109

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

LeetCode第347题_前K个高频元素

LeetCode 347题解:前K个高频元素 本文提供两种高效解法: 优先队列法(O(nlogk)):使用哈希表统计频率,小顶堆维护前K元素 桶排序法(O(n)):构建频率桶,从高到低收集结果 核心思路: 统计元素频率 优先队列动态维护K个最大值 桶排序避免完全排序 代码实现: 包含C#、Python、C++三种语言版本,均通过测试用例。 性能对比: 桶排序法时间复杂度更优,适合大数据量场景;优先队列法实现更简洁。

qq_40263592的博客 1526

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【leetcode】347. 前k个高频元素

这样堆中始终保存的是频率最高的 k 个元素。O(n log k):遍历 nums 中的 n 个元素,每次操作堆的时间复杂度为 O(log k),因此总时间复杂度为 O(n log k)。主要功能: 最小堆:heapq 默认实现的是最小堆(即堆顶是最小的元素)。最小堆的性质: 每个父节点的值都小于或等于其子节点的值,这使得堆顶元素始终是最小的元素。最小堆:通过 heapq 模块来实现最小堆,堆中存储的是 (频次, 数字) 元组。在 heapq 模块中,堆是用列表实现的,列表的第一个元素始终是堆顶元素。

qq_38473254的博客 1584

LeetCode347 前K个高频元素解题思路与实现

本文分析了LeetCode 347题"前K个高频元素"的三种解法:大顶堆、小顶堆和桶排序。大顶堆实现简单但效率较低(O(n log n));小顶堆优化空间复杂度(O(n+k)),适合k较小场景;桶排序最优(O(n)),但需预知最大频率值。文章详细对比了三种方法的时间/空间复杂度及适用场景,并提供了完整代码实现。在实际应用中应根据数据规模、k值大小和频率分布特征选择合适解法。

m0_74696257的博客 1155

LeetCode 347 前 K 个高频元素

LeetCode 347 前 K 个高频元素 题目链接 给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 示例 1: 输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] 示例 2: 输入: nums = [1], k = 1 输出: [1] 简单数据结构,AC代码如下: class Solution { public: vector<int> topKFrequent(vector<int>& nums, int k)

旺崽的博客 2643

【力扣347前k个高频元素】

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

qq_51931826的博客 289

LeetCode 347 前K个高频元素 Java

LeetCode 347 前K个高频元素 Java题目描述代码 题目描述 给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 示例 1: 输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] 示例 2: 输入: nums = [1], k = 1 输出: [1] 说明: 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。 你的算法...

qq_29061435的博客 133

【LeetCode】347.前 K 个高频元素

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

Leonardo_t的博客 608

golang力扣leetcode 347.前K个高频元素

347.前K个高频元素347.前K个高频元素题解代码 347.前K个高频元素 347.前K个高频元素 题解 题目:给一个数组,统计出现频率前k高的元素 思路: 1. 将元素和出现次数存入map 2. 快排出现次数 1.堆排序,小根堆 2.当堆中的元素大于k时,弹出堆顶,因为是小根堆,所有弹出的都是最小的出现次数 3.那么剩余堆中的k个元素就是出现频率前k高的元素了 注意Pop,我之前一直以为Pop是弹出末尾的元素,类似队列,结果Pop是弹出堆顶元素,并维护堆,那么对于小根堆来说,Pop就是弹出最小的元素

清风 659

LeetCode-347-前K个高频元素-C语言

/* * 算法思想: * 构建带权值哈希表,权值为出现次数; * 1. 首先排序,方便构建哈希表,使相同的值相邻; * 2. 排序哈希表,以哈希表的权值出现次数为排序元素; * 3. 从哈希表中提取k个排序结果即可。 **/ int cmp(int *a, int *b){ return *a - *b; } int cmp_node(int *a, int *b){ ...

SFFS 1246

LeetCode 347:前k个高频元素

LeetCode 347:前k个高频元素题目描述解题思路代码实现总结 题目描述 给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 示例 1: 输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2] 示例 2: 输入: nums = [1], k = 1 输出: [1] 说明: 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。 你...

香农三定律的博客 237
上一篇: Leetcode(215)——数组中的第K个最大元素
下一篇: Leetcode(695)——岛屿的最大面积
486L
博客等级 码龄7年 20粉丝 117原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值