中等
1.7K
相关企业
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
1 <= nums.length <= 105
k
的取值范围是[1, 数组中不相同的元素的个数]
- 题目数据保证答案唯一,换句话说,数组中前
k
个高频元素的集合是唯一的
进阶: 你所设计算法的时间复杂度 必须 优于 O(n log n)
,其中 n
**是数组大小。
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function(nums, k) {
let times = {}
nums.forEach(num=>{
if(times[num]!==undefined){
times[num]++
}else{
times[num]=1
}
})
let keys = Object.keys(times)
keys.sort((a,b)=>{
return times[b]-times[a]
})
return keys.slice(0,k)
};
这里让我们统计出现频次最高的k个高频元素
- 思路,先循环数组统计每个数字出现的频率,然后根据得到的数字频率进行排序,截取符合条件的k个元素return即可。
- 第一步声明一个变量times用于接受统计的各个数字的次数
- 循环数字数组统计数字出现的次数,如果该数组在times中出现过,则该数字次数加一,否则在times中新增一个key为当前数字的元素,值为1,这里也可以利用map统计每个元素出现的次数使用map时。注意点:map不能直接排序,可以通过Array.from或展开运算符将Map转化为二维数组进行排序。
- 循环完毕后,使用Object.keys()获取times的key,即数字数组中出现的所有的数字,然后对所有出现的数字进行排序keys.sort((a,b)=>{ return times[b]-times[a] })这里使用sort排序,根据之前统计的times,对所有出现的数据进行从大到小的排序。 4.已知题目要求我们返回出现频次最高的k个元素,这里我们直接从0开始截取排序后的keys(出现的所有的数字按照从大到小排序后)k个元素返回即可。
如果是按照从小到大的顺序排的keys,截取keys数组的后k位元素。
进阶算法的话,不会,但是找到个大佬的。
优先队列
思路:循环数组,加入小顶堆,当堆的size超过k时,出堆,循环完成之后,堆中所有的元素就是前k大的数字 复杂度:时间复杂度O(nlogk),循环n次,每次堆的操作是O(logk)。空间复杂度O(k),
作者:晨 链接:leetcode.cn/problems/to… 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
constructor(comparator = (a, b) => a - b, data = []) {
this.data = data;
this.comparator = comparator;//比较器
this.heapify();//堆化
}
heapify() {
if (this.size() < 2) return;
for (let i = Math.floor(this.size()/2)-1; i >= 0; i--) {
this.bubbleDown(i);//bubbleDown操作
}
}
peek() {
if (this.size() === 0) return null;
return this.data[0];//查看堆顶
}
offer(value) {
this.data.push(value);//加入数组
this.bubbleUp(this.size() - 1);//调整加入的元素在小顶堆中的位置
}
poll() {
if (this.size() === 0) {
return null;
}
const result = this.data[0];
const last = this.data.pop();
if (this.size() !== 0) {
this.data[0] = last;//交换第一个元素和最后一个元素
this.bubbleDown(0);//bubbleDown操作
}
return result;
}
bubbleUp(index) {
while (index > 0) {
const parentIndex = (index - 1) >> 1;//父节点的位置
//如果当前元素比父节点的元素小,就交换当前节点和父节点的位置
if (this.comparator(this.data[index], this.data[parentIndex]) < 0) {
this.swap(index, parentIndex);//交换自己和父节点的位置
index = parentIndex;//不断向上取父节点进行比较
} else {
break;//如果当前元素比父节点的元素大,不需要处理
}
}
}
bubbleDown(index) {
const lastIndex = this.size() - 1;//最后一个节点的位置
while (true) {
const leftIndex = index * 2 + 1;//左节点的位置
const rightIndex = index * 2 + 2;//右节点的位置
let findIndex = index;//bubbleDown节点的位置
//找出左右节点中value小的节点
if (
leftIndex <= lastIndex &&
this.comparator(this.data[leftIndex], this.data[findIndex]) < 0
) {
findIndex = leftIndex;
}
if (
rightIndex <= lastIndex &&
this.comparator(this.data[rightIndex], this.data[findIndex]) < 0
) {
findIndex = rightIndex;
}
if (index !== findIndex) {
this.swap(index, findIndex);//交换当前元素和左右节点中value小的
index = findIndex;
} else {
break;
}
}
}
swap(index1, index2) {//交换堆中两个元素的位置
[this.data[index1], this.data[index2]] = [this.data[index2], this.data[index1]];
}
size() {
return this.data.length;
}
}
var topKFrequent = function (nums, k) {
const map = new Map();
for (const num of nums) {//统计频次
map.set(num, (map.get(num) || 0) + 1);
}
//创建小顶堆
const priorityQueue = new Heap((a, b) => a[1] - b[1]);
//entry 是一个长度为2的数组,0位置存储key,1位置存储value
for (const entry of map.entries()) {
priorityQueue.offer(entry);//加入堆
if (priorityQueue.size() > k) {//堆的size超过k时,出堆
priorityQueue.poll();
}
}
const ret = [];
for (let i = priorityQueue.size() - 1; i >= 0; i--) {//取出前k大的数
ret[i] = priorityQueue.poll()[0];
}
return ret;
};
作者:晨
链接:https://leetcode.cn/problems/top-k-frequent-elements/solutions/1119211/347-qian-k-ge-gao-pin-yuan-su-by-chen-we-173k/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。