Skip to content

Commit 7fc5ab4

Browse files
committed
feat: 增加题解347.前 K 个高频元素
1 parent 9bccd66 commit 7fc5ab4

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@
112112
### 哈希表
113113

114114
- [x] [【day-19】1.两数之和](./basic/hashmap/19.two-sum.md)
115+
- [x] [【day-20】347.前 K 个高频元素](./basic/hashmap/20.top-k-frequent-elements.md)
116+
115117
- [x] [【day-20】447.回旋镖的数量](./basic/day-20.md)
116118
- [ ] 【day-21】36.有效的数独
117119
- [x] [【day-22】645.错误的集合](./basic/day-22.md)
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# 347. 前 K 个高频元素
2+
3+
https://leetcode-cn.com/problems/top-k-frequent-elements/
4+
5+
- [347. 前 K 个高频元素](#347-前-k-个高频元素)
6+
- [题目描述](#题目描述)
7+
- [方法 1:哈希表](#方法-1哈希表)
8+
- [思路](#思路)
9+
- [复杂度分析](#复杂度分析)
10+
- [代码](#代码)
11+
- [方法 2:大顶堆](#方法-2大顶堆)
12+
- [思路](#思路-1)
13+
- [复杂度分析](#复杂度分析-1)
14+
- [代码](#代码-1)
15+
16+
## 题目描述
17+
18+
```
19+
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
20+
21+
 
22+
23+
示例 1:
24+
25+
输入: nums = [1,1,1,2,2,3], k = 2
26+
输出: [1,2]
27+
示例 2:
28+
29+
输入: nums = [1], k = 1
30+
输出: [1]
31+
 
32+
33+
提示:
34+
35+
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
36+
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
37+
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
38+
你可以按任意顺序返回答案。
39+
40+
来源:力扣(LeetCode)
41+
链接:https://leetcode-cn.com/problems/top-k-frequent-elements
42+
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
43+
```
44+
45+
## 方法 1:哈希表
46+
47+
### 思路
48+
49+
- 遍历一遍数组,用哈希表统计每个数字出现的次数。
50+
- 按次数排序,然后输出前 k 个数字。
51+
52+
### 复杂度分析
53+
54+
- 时间复杂度:$O(mlogm)$,m 是数组中不同数字的数量,最大是 N,数组的长度,这是排序的时间。
55+
- 空间复杂度:$O(m)$,m 是数组中不同数字的数量,哈希表的空间。
56+
57+
### 代码
58+
59+
JavaScript Code
60+
61+
```js
62+
/**
63+
* @param {number[]} nums
64+
* @param {number} k
65+
* @return {number[]}
66+
*/
67+
var topKFrequent = function (nums, k) {
68+
// 统计出现次数
69+
const map = {};
70+
for (const n of nums) {
71+
n in map || (map[n] = 0);
72+
map[n]++;
73+
}
74+
// 对次数进行排序然后输出前 k 个
75+
return Object.entries(map)
76+
.sort((a, b) => b[1] - a[1])
77+
.slice(0, k)
78+
.map(a => a[0]);
79+
};
80+
```
81+
82+
## 方法 2:大顶堆
83+
84+
### 思路
85+
86+
看到 `前 k 个` 这种描述就能想到 `` 了,还是先把数字出现的次数统计在哈希表中,然后入堆按次数排序,再吐出来 k 个。
87+
88+
### 复杂度分析
89+
90+
- 时间复杂度:$O(klogm)$,m 是数组中不同数字的数量,堆中有 m 个元素,移除堆顶的时间是 $logm$,重复操作了 k 次。
91+
- 空间复杂度:$O(m)$,m 是数组中不同数字的数量,哈希表和堆的空间。
92+
93+
### 代码
94+
95+
JavaScript Code
96+
97+
```js
98+
/**
99+
* @param {number[]} nums
100+
* @param {number} k
101+
* @return {number[]}
102+
*/
103+
var topKFrequent = function (nums, k) {
104+
// 统计出现次数
105+
const map = {};
106+
for (const n of nums) {
107+
n in map || (map[n] = 0);
108+
map[n]++;
109+
}
110+
// 入堆,格式是:[数字,次数],按次数排序
111+
const maxHeap = new MaxHeap(Object.entries(map), function comparator(
112+
target,
113+
compared,
114+
) {
115+
return target[1] < compared[1];
116+
});
117+
// 输出前 k 个
118+
const res = [];
119+
while (k-- > 0) {
120+
res.push(maxHeap.pop()[0]);
121+
}
122+
return res;
123+
};
124+
125+
// *******************************************
126+
127+
class Heap {
128+
constructor(list = [], comparator) {
129+
this.list = list;
130+
131+
if (typeof comparator != 'function') {
132+
this.comparator = function comparator(target, compared) {
133+
return target < compared;
134+
};
135+
} else {
136+
this.comparator = comparator;
137+
}
138+
139+
this.init();
140+
}
141+
142+
init() {
143+
const size = this.size();
144+
for (let i = Math.floor(size / 2) - 1; i >= 0; i--) {
145+
this.heapify(this.list, size, i);
146+
}
147+
}
148+
149+
insert(n) {
150+
this.list.push(n);
151+
const size = this.size();
152+
for (let i = Math.floor(size / 2) - 1; i >= 0; i--) {
153+
this.heapify(this.list, size, i);
154+
}
155+
}
156+
157+
peek() {
158+
return this.list[0];
159+
}
160+
161+
pop() {
162+
const last = this.list.pop();
163+
if (this.size() === 0) return last;
164+
const returnItem = this.list[0];
165+
this.list[0] = last;
166+
this.heapify(this.list, this.size(), 0);
167+
return returnItem;
168+
}
169+
170+
size() {
171+
return this.list.length;
172+
}
173+
}
174+
175+
class MaxHeap extends Heap {
176+
constructor(list, comparator) {
177+
super(list, comparator);
178+
}
179+
180+
heapify(arr, size, i) {
181+
let largest = i;
182+
const left = Math.floor(i * 2 + 1);
183+
const right = Math.floor(i * 2 + 2);
184+
185+
if (left < size && this.comparator(arr[largest], arr[left]))
186+
largest = left;
187+
if (right < size && this.comparator(arr[largest], arr[right]))
188+
largest = right;
189+
190+
if (largest !== i) {
191+
[arr[largest], arr[i]] = [arr[i], arr[largest]];
192+
this.heapify(arr, size, largest);
193+
}
194+
}
195+
}
196+
```

0 commit comments

Comments
 (0)