一个算法题带你搞懂<堆结构>:347、给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

一、问题

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

示例一:

输入: nums = [1,1,1,2,2,3], k = 2

输出: [1,2]

示例二:

输入: nums = [1], k = 1

输出: [1]

提示:

● 1 <= nums.length <= 105

● k 的取值范围是 [1, 数组中不相同的元素的个数]

● 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

进阶: 你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小

二、思路

1、统计元素出现频率 map结构:(key,value) key存放元素值,value存放出现次数,遍历整个数组求出每个元素的出现频次,时间复杂度O(logn);

2、对频率排序 按照value值进行排序;

3、找出前K个高频元素。

堆排序:nlog(n)

堆排序:维持前K个高频元素的有序集合,如K=3

三、堆相关知识

3.1 堆的相关定义

定义:堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。 故通常我们用完全二叉树来维护一个一维数组。

性质

1)堆中某个节点的值总是不大于或不小于其父节点的值。

2)堆总是一棵完全二叉树。

完全二叉树:

满足下面两点:

1)如果将二叉树的深度设置为h,则除h层之外的所有层(1~h-1)中的节点数达到最大值(满二叉树)

2)并且h层中的所有节点都连续地集中在最左侧

就是一个完全的二叉树。

3.2 堆的分类

1)大根堆:一棵完全二叉树,满足任一节点都比其孩子节点大。

2)小根堆:一棵完全二叉树,满足任一节点都比其孩子节点小。

3.3 构建堆

以大根堆为例:

给定初始数组:[2, 9, 7, 8, 5, 0, 1, 6, 4, 3]

3.3.1 堆的向下调整性

(大根堆为例)

假设根节点的左右子树都是堆,但是根节点不满足堆的性质,可以通过一次向下调整来将其变成一个堆。

1)初始的树结构如下图,根节点2无法成堆,但其左右子树均能成大根堆

2)变更2的位置,先取出数值2,对比其孩子节点大小,9比7大,9移动到根节点的位置。

3)如果移动到空位上,8和5都比2大,显然不成立。因此需要移动空位下一层节点中更大的值到该空位中,8大于5,将8移动到空位中。

4)同理,2移动到现有空位上,6和4都大于2,堆无法成立。同上步骤,选择6和4中较大的值移动到空位

5)现有空位为叶子节点,已经是堆的最小节点,移动2到空位上,这时,原先的完全二叉树变为大根堆。

以上整个移动过程,就是一次堆的向下调整。

3.3.2 堆排序过程

(1)建立堆;

(2)得到堆顶元素,为最大元素;

(3)去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一次调整重新使堆有序;

(4)堆顶元素为第二大元素;

(5)重复步骤3,直到堆变空。

四、题解

1、统计元素出现频率 map结构:(key,value) key存放元素值,value存放出现次数,遍历整个数组求出每个元素的出现频次,时间复杂度O(logn);

2、对频率排序 按照value值进行排序;

1)如图,大根堆堆顶是列表中最大的数。取走9,得到列表中第一大的数。

2)取堆中最后一个元素,这里是3,将3移动到堆顶,得到一个除了根节点外,子树都是堆的完全二叉树

3)向下调整,得到如下图的大根堆。

如图,大根堆堆顶是列表中最大的数。取走8,得到列表中第二大的数。

4)重复2)3)过程直至取到的个数为k

3、找出前K个高频元素,输出结果

  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值