Open azl397985856 opened 2 years ago
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function (nums, k) {
let map = {};
for (let num of nums) {
if (map[num] === undefined) {
map[num] = 1;
} else {
map[num] += 1;
}
}
return Object.entries(map).sort((a, b) => b[1] - a[1]).slice(0,k).map(i => i[0])
};
复杂度分析不是很会,不一定对,如果有错,请指正。
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function (nums, k) {
let map = {};
for (let num of nums) {
if (map[num] === undefined) {
map[num] = 1;
} else {
map[num] += 1;
}
}
let arr = [];
Object.entries(map).map((item) => {
if (arr[item[1]] === undefined) {
arr[item[1]] = [item[0]];
} else {
arr[item[1]].push(item[0]);
}
});
let ans = [];
for (let i = arr.length - 1; i >= 0 && ans.length < k; i--) {
arr[i] && ans.push(...arr[i]);
}
return ans;
};
复杂度分析不是很会,不一定对,如果有错,请指正。
思路 ummmmm 大概类似topk明天再写今天懒了=。= 调库yyds
代码
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
count = collections.Counter(nums)
return [item[0] for item in count.most_common(k)]
复杂度 时间 O(nlogn) 空间 O(n)
思路一: 先用一个data结构体来存次数和值。 遍历数组,用哈希表存次数。 遍历哈希表,将值和次数存在data数组。 对data数组排序,并将值赋值给输出数组ans
type data struct{
num int
times int
}
func topKFrequent(nums []int, k int) []int {
hashmap := map[int]int{}
for _,x := range nums{
hashmap[x]++
}
out := []data{}
for i,x := range hashmap{
out = append(out,data{num:i,times:x})
}
sort.Slice(out,func(i,j int) bool{
return out[i].times > out[j].times
})
ans := make([]int,k)
for i:=0;i<k;i++{
ans[i] = out[i].num
}
return ans
}
时间复杂度O(nlogn) 空间复杂度O(n)
思路二: 采用堆排序处理TOPK类型。 对于GO语言来说,要使用堆需要构建五个函数,分别是Len(),Less(),Swap(),Push(),Pop() 其中Less决定是大顶堆还是小顶堆。再最开始的 type Iheap [][2]int 其中的[2]int指的是堆中存放的数据。 这里存放一个二元组,0表示数据,1表示次数。 构建完之后其他思路同之前一样,哈希表存次数,入堆。如果堆的数量大于K则出堆【这里选用最小堆】 最后,构建一个out数组,从后往前 从堆顶拿数据,get answer!
type Iheap [][2]int
func (h Iheap) Len() int{ return len(h)}
func (h Iheap) Less(i,j int) bool{return h[i][1]<h[j][1]}
func (h Iheap) Swap(i,j int) {h[i],h[j] = h[j],h[i]}
func (h *Iheap) Push (x interface{}){
*h = append(*h,x.([2]int))
}
func (h *Iheap) Pop () interface{}{
out := *h
x := out[len(out)-1]
*h = out[:len(out)-1]
return x
}
func topKFrequent(nums []int, k int) []int {
hash := map[int]int{}
for _,x:= range nums{
hash[x]++
}
h := &Iheap{}
heap.Init(h)
for key,value := range hash{
heap.Push(h,[2]int{key,value})
if h.Len() > k{
heap.Pop(h)
}
}
out := make([]int,k)
for i:=k-1;i>=0;i--{
out[i] = heap.Pop(h).([2]int)[0]
}
return out
}
时间复杂度O(NlogN) 空间复杂度O(N)
桶排序
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
from collections import defaultdict
d=defaultdict(int)
mx=0
for i in nums:
d[i]+=1
mx=max(mx,d[i])
res=[[] for _ in range(mx+1)]
for key,v in list(d.items()):
res[v].append(key)
final=[]
while len(final)<k and len(res)>0:
final=final+res[-1]
res.pop()
return final
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> re;
sort(nums.begin(),nums.end());
// count, value
vector<tuple<int,int>> tp;
int last_val = INT_MIN;
int count = 0;
for(auto & num:nums){
if(last_val!=num){
tp.emplace_back(count,last_val);
count = 1;
last_val = num;
continue;
}
count++;
}
//情况没有考虑全
tp.emplace_back(count,last_val);
sort(tp.begin(),tp.end(),greater<>());
for(int i=0;i<k;i++){
re.emplace_back(get<1>(tp[i]));
}
return re;
}
};
class Solution(object): def topKFrequent(self, nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ if k == len(nums): return nums
dictHelper = {}
for num in nums:
if num not in dictHelper:
dictHelper[num] = 1
else:
dictHelper[num] += 1
return heapq.nlargest(k, dictHelper.keys(), dictHelper.get)
利用hashmap记录frequency,再利用heapsort得到k largest、
import heapq as hp
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
a = defaultdict(int)
for num in nums:
a[num]+=1
b = []
for key in a:
b.append((-a[key],key))
hp.heapify(b)
result = []
for i in range(k):
result.append(hp.heappop(b)[1])
return result
复杂度分析
Day20 347 https://leetcode-cn.com/problems/top-k-frequent-elements/
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> ans;
unordered_map<int, int> hash;
priority_queue<pair<int, int>> q;
for(auto& num : nums) hash[num]++;
for(auto& item: hash) q.push(make_pair(item.second, item.first));
while(k--){
ans.push_back(q.top().second);
q.pop();
}
return ans;
}
};
Complexity
Thoughts
Code
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
int[] res = new int[k];
for (int num: nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
PriorityQueue<Integer> heap = new PriorityQueue<Integer>((a, b) -> map.get(a) - map.get(b));
for (Integer key: map.keySet()) {
if (heap.size() < k) {
heap.add(key);
} else if (map.get(key) > map.get(heap.peek())) {
heap.remove();
heap.add(key);
}
}
int idx = k - 1;
while (!heap.isEmpty()) {
res[idx--] = heap.remove();
}
return res;
}
Complexity
O(n)
O(n)
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
#O(n)
nums_dict = {}
res = [[] for i in range(len(nums)+1)]
for i in nums:
nums_dict[i] =nums_dict.get(i,0)+1
for num, times in nums_dict.items():
res[times].append(num)
ans = []
for i in range(len(nums), 0, -1):
if len(res[i]) == 0:
continue
ans.extend(res[i])
if len(ans) == k:
return ans
思路
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
if len(nums) == k: return nums
d = {}
res = []
for num in nums:
if num in d:
d[num] += 1
else:
d[num] = 1
h = []
for key in d:
heappush(h, (d[key], key))
if len(h) > k:
heappop(h)
while h:
frq, item = heappop(h)
res.append(item)
return res
复杂度分析
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
count = collections.Counter(nums)
return [item[0] for item in count.most_common(k)]
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
d = dict()
for num in nums:
if num not in d.keys():
d[num] = 1
else:
d[num] += 1
maxHeap = [[-freq, num] for num, freq in d.items()]
heapq.heapify(maxHeap)
ans = []
for i in range(k):
_, num = heapq.heappop(maxHeap)
ans.append(num)
return ans
Time Complexity: O(NlogK), Space Complexity: O(n)
from collections import Counter
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
if nums:
c = Counter(nums)
# the size of pool is k
pool = dict()
pool_min_val = float("inf")
pool_min_key = 0
for key, val in c.items():
# add to pool until size of pool = k
if len(pool) < k:
pool[key] = val
# update the min key and min val
if val < pool_min_val:
pool_min_val = val
pool_min_key = key
# once pool is full, remove smallest one if find bigger one
else:
if val > pool_min_val:
del pool[pool_min_key]
pool[key] = val
# update the smallest values
pool_min_key = min(pool, key=pool.get)
pool_min_val = pool[pool_min_key]
return list(pool.keys())
else:
return []
time O(N), space O(N)
用hashmap做最简单,主要是熟练hashmap的api使用,最后用set转成没有重复元素的数组,排序截取即可
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function(nums, k) {
let map = new Map();
nums.map((item)=>{
if(map.has(item)){
map.set(item,map.get(item)+1);
}else{
map.set(item,1);
}
});
let arr = [...new Set(nums)];
console.log(arr);
arr.sort((a,b)=>map.get(b)-map.get(a));
// reverse order by frequency
return arr.splice(0,k);
};
时间复杂度应该是排序算法的时间复杂度,空间复杂度O(N)
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
#Solution1:
#先把每个num遍历一遍,用字典。
#然后排序(将字典转化为列表l,对列表l按照频次进行排序(利用匿名函数;倒序)。
#再把前k个取出来。
dict= {}
for i in range(len(nums)):
if nums[i] not in dict:
dict[nums[i]] = 1
if nums[i] in dict:
dict[nums[i]] += 1
l = list(dict.items())
l.sort(key = lambda x : x[1], reverse = True)
res=[]
for i in range(k):
res.append(l[i][0])
return res
# #Solution 2 直接排序
# #记录每个数字出现的次数
# #返回次数最高的前k个数
# #时间复杂度O(NlogN)
# #空间复杂度O(N)
# count = collections.Counter(nums)
# return [item[0] for item in count.most_common(k)]
# #solution 3 堆
# #记录每个数字出现的次数
# #把这个数和出现的次数放在heap中
# #返回heap中前k个对大元素
# #时间复杂度O(NlogN)
# #空间复杂度O(N)
# count = collections.Counter(nums)
# heap = [(val, key) for key, val in count.items()]
# return [item[1] for item in heapq.nlargest(k, heap)]
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for(int num : nums) {
if(map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
Queue<Integer> queue = new PriorityQueue<>((a, b) -> map.get(a) - map.get(b));
for(int num : map.keySet()) {
if(queue.size() < k) {
queue.offer(num);
} else if(map.get(num) > map.get(queue.peek())) {
queue.poll();
queue.offer(num);
}
}
int[] res = new int[k];
for(int i = 0; i < k; i++) {
res[i] = queue.poll();
}
return res;
}
}
复杂度分析
# solution 2: use min heap
# build counter
# heappush (freq, num)
# heappop if curr heap length is greater than k
# (aka removed number that has the lowest freq)
# (aka keep a heap list with elements with max freq so far)
# time: O(NlogK)
# space: o(N)
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
counter = defaultdict(int)
min_heap = []
for num in nums:
counter[num] += 1
for num in counter.keys():
# min heap of top k items
heapq.heappush(min_heap, (counter[num], num))
if len(min_heap) > k:
heapq.heappop(min_heap)
res = []
for freq, num in min_heap:
res.append(num)
return res
C++ Code:
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> record;
for(int i=0; i< nums.size(); i++)
{
record[nums[i]]++;
}
auto comp = [](pair<int,int>& node1, pair<int,int>&node2)
{
if(node1.second ==node2.second) return node1.first < node2.first;
return node1.second > node2.second;
};
priority_queue<pair<int,int>, vector<pair<int,int>>, decltype(comp)> pq(comp);
for(auto it = record.begin(); it!=record.end(); it++)
{
if(pq.size()<k)
{
pq.push((*it));
}
else
{
if((*it).second>pq.top().second)
{
pq.pop();
pq.push((*it));
}
}
}
vector<int> ret;
while(pq.size())
{
ret.push_back(pq.top().first);
pq.pop();
}
return ret;
}
};
Heap + HashTable. First use hash table to record each unique element's frequency. Then, scan over the hash table. If current heap length smaller than k, push [current element frequency, current element] in to the heap. Otherwise, if current element's frequency larger than k, pop out first pair in heap, and push current pair to heap.
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
count = collections.Counter(nums)
heap= []
for i in count:
if len(heap) == k and count[i] > heap[0][0]:
heapq.heappop(heap)
heapq.heappush(heap,[count[i],i])
elif len(heap)<k:
heapq.heappush(heap,[count[i],i])
return [i[1] for i in heap]
Time: O(NlogK) Space: O(N)
Python3 Code:
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
from collections import Counter
counter = Counter(nums).most_common(k)
# print([key for key,val in counter])
return [key for key,val in counter]
遍历数组,将每个数字出现个数存入map中,构建一个新结构体,参数是map的key和value,将map中的元素出入结构体列表中,通过value大小排序,返回前K个
type newMap struct {
key int
value int
}
type newMapSlice []newMap
func (s newMapSlice) Len() int {
return len(s)
}
func (s newMapSlice) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s newMapSlice) Less(i, j int) bool {
return s[i].value>s[j].value
}
func topKFrequent(nums []int, k int) []int {
hashmap := map[int]int{}
for _,num := range nums{
hashmap[num] += 1
}
newmapslice := newMapSlice{}
ans := make([]int, 0)
for key,value := range hashmap{
newmap := newMap{key,value}
newmapslice = append(newmapslice, newmap)
}
sort.Sort(newmapslice)
for i:= 0;i<k;i++{
ans = append(ans, newmapslice[i].key)
}
return ans
}
时间:O(n) 空间:O(n)
使用哈希表统计频率,使用堆找出前k个高频出现的元素
class Solution
{
public:
vector<int> topKFrequent(vector<int>& nums, int k)
{
vector<int> res;
unordered_map<int,int> m;
priority_queue<pair<int,int>> q;
for(int i=0;i<nums.size();i++)
m[nums[i]] ++;
for(auto p : m)
q.push(pair<int,int> (p.second,p.first));
while(k--)
{
res.push_back(q.top().second);
q.pop();
}
return res;
}
};
class Solution: def topKFrequent(self, nums: List[int], k: int) -> List[int]: dic = defaultdict(int) for i in nums: dic[i] += 1
dic = sorted(dic, key=dic.get, reverse=True)
#print(dic)
ans = []
kk = 0
for key in dic:
#print(key)
ans.append(key)
kk += 1
if kk == k:
break
return ans
class Solution(object):
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
count = collections.Counter(nums)
heap = []
for key, val in count.items():
if len(heap) >= k:
if val > heap[0][0]:
heapq.heapreplace(heap, (val, key))
else:
heapq.heappush(heap, (val, key))
return [item[1] for item in heap]
时间复杂度:O(nlogk)
空间复杂度:O(n)
//s6
//s6 heap
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
for(int num: nums){
map.put(num, map.getOrDefault(num, 0) + 1);
}
PriorityQueue<int[]> heap = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);
for(int key: map.keySet()){
if(heap.size() == k && heap.peek()[1] < map.get(key)) {
heap.poll();
}
if(heap.size() < k){
heap.add(new int[]{key, map.get(key)});
}
}
int[] res = new int[k];
for(int i = 0;i < res.length;i++){
res[i] = heap.poll()[0];
}
return res;
}
}
//s6 bucket
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
for(int num: nums){
map.put(num, map.getOrDefault(num, 0) + 1);
}
List<Integer>[] sum = new ArrayList[nums.length];
for(int key: map.keySet()){
int count = map.get(key);
if(sum[count - 1] == null) {
sum[count - 1] = new ArrayList<>();
}
sum[count - 1].add(key);
}
int[] res = new int[k];
int index = 0;
for(int i = sum.length - 1;i >= 0;i--){
if(index == k){
return res;
} else if(sum[i] != null) {
for(int j = 0;j < sum[i].size();j++){
res[index] = sum[i].get(j);
index++;
}
}
}
return res;
}
}
//heap time: O(NlogN),每次存入logN,存N次; space:heap所需的空间O(D), D是不同的元素的个数,最坏为O(N)
//hashmap+ArrayList
CODE :
public List<Integer> topKFrequent2(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
PriorityQueue<Map.Entry<Integer, Integer>> maxHeap =
new PriorityQueue<>((a, b) -> (b.getValue() - a.getValue()));
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
maxHeap.add(entry);
}
List<Integer> res = new ArrayList<>();
while (res.size() < k) { // O(klogn)
Map.Entry<Integer, Integer> entry = maxHeap.poll();
res.add(entry.getKey());
}
return res;
}
先用 哈希表 将数组中出现的元素次数存下来。
然后对 哈希表 进行一个排序,在取排序 前 k 个数即可。
var topKFrequent = function (nums, k) {
const map = {}
nums.forEach((i) => {
if (map[i] === undefined) {
map[i] = 1
} else {
map[i] += 1
}
})
const entries = Object.entries(map)
const sorted_entries = entries.sort((a, b) => b[1] - a[1])
const res = sorted_entries.map((i) => i[0])
return res.slice(0, k)
}
用map记录每个值出现过的频率,在对map的key进行排序,排序依据是通过value的大小
JavaScript Code:
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function(nums, k) {
let map = {}
let res = []
for(let i = 0; i<nums.length; i++) {
map[[nums[i]]] = map[[nums[i]]] ? map[[nums[i]]] + 1 : 1
}
let keys = Object.keys(map)
keys.sort((a, b) => map[b] - map[a])
while(k > 0) {
let key = keys.shift()
res.push(key)
k--
}
return res
};
复杂度分析
令 n 为数组长度。
var topKFrequent = function (nums, k) {
let map = new Map()
let arr = [...new Set(nums)]
nums.map((num) => {
if (map.has(num))
map.set(num, map.get(num) + 1)
else
map.set(num, 1)
})
return arr.sort((a, b) => map.get(b) - map.get(a)).slice(0, k)
};
思路比较清晰,先用HashMap轮询一遍,找到离散的每个数字对应出现的频率。 然后把 EntrySet 拿出来从高往低排序。 获取前K个Entry.Key 输出即可。
import java.util.*;
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public int[] topKFrequent(int[] nums, int k) {
LinkedHashMap<Integer, Integer> linkedHashMap = new LinkedHashMap<>();
for (int i = 0; i < nums.length; i++) {
if (linkedHashMap.containsKey(nums[i])) {
linkedHashMap.put(nums[i], linkedHashMap.get(nums[i]) + 1);
} else {
linkedHashMap.put(nums[i], 1);
}
}
List<Map.Entry<Integer, Integer>> list = new ArrayList<>(linkedHashMap.entrySet());
Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>() {
@Override
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
return o2.getValue() - o1.getValue();
}
});
int[] ans = new int[k];
for (int i = 0; i < list.size() && i < k; i++) {
ans[i] = list.get(i).getKey();
}
return ans;
}
}
//leetcode submit region end(Prohibit modification and deletion)
桶排序 + 哈希表
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
count = {}
# empty array with the size of nums + 1
frequency = [[] for i in range(len(nums) + 1)]
# count each value, if not exist, set to default 0
for n in nums:
count[n] = 1 + count.get(n, 0)
# going through each counted value
for n, c in count.items():
frequency[c].append(n) # the value n appears c times
res = []
# find most frequent value
for i in range(len(frequency) - 1, 0, -1): # start from last element to 0, step is -1
for n in frequency[i]: # go through every value in index i
res.append(n)
if len(res) == k:
return res
直观思路,遍历数组统计数字出现的次数,按次数排序后输出前 k 个数字,可以使用哈希表来记录。
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> count;
for (int n : nums)
count[n]++;
// sort map by value
vector<pair<int, int>> freq(count.begin(), count.end());
sort(freq.begin(), freq.end(), [](pair<int, int>& a, pair<int, int>& b) { return a.second > b.second; });
vector<int> res;
res.reserve(k);
int i = 0;
while (i < k) {
res.emplace_back(freq[i++].first);
}
return res;
}
};
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function (nums, k) {
// 统计出现次数
const map = {};
for (const n of nums) {
n in map || (map[n] = 0);
map[n]++;
}
// 对次数进行排序然后输出前 k 个
return Object.entries(map)
.sort((a, b) => b[1] - a[1])
.slice(0, k)
.map(a => a[0]);
};
看到 求前 k 个
这样的描述自然会联想到用 堆
来进行排序。
大顶堆
的话,需要将所有 [数字, 次数]
元组都入堆,再进行 k 次取极值的操作。小顶堆
的话,只需要维持堆的大小一直是 k 即可。大顶堆
class Solution {
public:
using Pair = pair<int, int>;
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> count;
for (int n : nums)
count[n]++;
// 大顶堆
auto cmp = [](Pair a, Pair b) { return a.second < b.second; };
priority_queue<Pair, vector<Pair>, decltype(cmp)> pq(count.begin(), count.end(), cmp);
vector<int> res;
res.reserve(k);
int i = 0;
while (i++ < k) {
res.emplace_back(pq.top().first);
pq.pop();
}
return res;
}
};
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function (nums, k) {
// 统计出现次数
const map = {};
for (const n of nums) {
n in map || (map[n] = 0);
map[n]++;
}
// 入堆,格式是:[数字,次数],按次数排序
const maxHeap = new MaxHeap(Object.entries(map), function comparator(
inserted,
compared,
) {
return inserted[1] < compared[1];
});
// 输出前 k 个
const res = [];
while (k-- > 0) {
res.push(maxHeap.pop()[0]);
}
return res;
};
// *******************************************
class Heap {
constructor(list = [], comparator) {
this.list = list;
if (typeof comparator != 'function') {
this.comparator = function comparator(inserted, compared) {
return inserted < compared;
};
} else {
this.comparator = comparator;
}
this.init();
}
init() {
const size = this.size();
for (let i = Math.floor(size / 2) - 1; i >= 0; i--) {
this.heapify(this.list, size, i);
}
}
insert(n) {
this.list.push(n);
const size = this.size();
for (let i = Math.floor(size / 2) - 1; i >= 0; i--) {
this.heapify(this.list, size, i);
}
}
peek() {
return this.list[0];
}
pop() {
const last = this.list.pop();
if (this.size() === 0) return last;
const returnItem = this.list[0];
this.list[0] = last;
this.heapify(this.list, this.size(), 0);
return returnItem;
}
size() {
return this.list.length;
}
}
class MaxHeap extends Heap {
constructor(list, comparator) {
super(list, comparator);
}
heapify(arr, size, i) {
let largest = i;
const left = Math.floor(i * 2 + 1);
const right = Math.floor(i * 2 + 2);
if (left < size && this.comparator(arr[largest], arr[left]))
largest = left;
if (right < size && this.comparator(arr[largest], arr[right]))
largest = right;
if (largest !== i) {
[arr[largest], arr[i]] = [arr[i], arr[largest]];
this.heapify(arr, size, largest);
}
}
}
小顶堆
class Solution {
public:
using Pair = pair<int, int>;
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> count;
for (int n : nums)
count[n]++;
// 小顶堆
auto cmp = [](Pair a, Pair b) { return a.second > b.second; };
priority_queue<Pair, vector<Pair>, decltype(cmp)> pq(cmp);
for (Pair p : count) {
if (pq.size() < k) {
pq.push(p);
} else if (pq.size() == k && p.second > pq.top().second) {
pq.pop();
pq.push(p);
}
}
vector<int> res;
res.reserve(k);
int i = k;
while (--i >= 0) {
res.emplace(res.begin(), pq.top().first);
pq.pop();
}
return res;
}
};
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function (nums, k) {
// 统计出现次数
const map = {};
for (const n of nums) {
n in map || (map[n] = 0);
map[n]++;
}
const minHeap = new MinHeap([], function comparator(inserted, compared) {
return inserted[1] > compared[1];
});
// 维护一个大小为 k 的小顶堆,堆元素格式是:[数字,次数],按次数排序
Object.entries(map).forEach(([num, times]) => {
const [, minTimes] = minHeap.peek() || [, 0];
// 小顶堆大小还没达到 k,继续插入新元素
if (minHeap.size() < k) {
minHeap.insert([num, times]);
}
// 小顶堆大小为 k,如果新元素次数大于堆顶,弹出堆顶,插入新元素
// 否则就不用管这个元素了
else if (minHeap.size() === k && times > minTimes) {
minHeap.pop();
minHeap.insert([num, times]);
}
});
// 反序输出小顶堆中的所有元素
const res = Array(k);
while (k-- > 0) {
res[k] = minHeap.pop()[0];
}
return res;
};
// *************************************
class MinHeap extends Heap {
constructor(list, comparator) {
if (typeof comparator != 'function') {
comparator = function comparator(inserted, compared) {
return inserted > compared;
};
}
super(list, comparator);
}
heapify(arr, size, i) {
let smallest = i;
const left = Math.floor(i * 2 + 1);
const right = Math.floor(i * 2 + 2);
if (left < size && this.comparator(arr[smallest], arr[left]))
smallest = left;
if (right < size && this.comparator(arr[smallest], arr[right]))
smallest = right;
if (smallest !== i) {
[arr[smallest], arr[i]] = [arr[i], arr[smallest]];
this.heapify(arr, size, smallest);
}
}
}
大顶堆
小顶堆
m >= k
。既然只是求前 k 个高频数字,便可不必对数组进行完全排序,局部排序算法 快速选择 - Quick Select 就是为这道题而生的。
虽然快速选择的目的只是找到第 k 大(小) 数字,但看结果我们也把前 k 大(小) 数字都归拢到了数组开头,且本题对返回结果的顺序不做要求,所以当我们用快速选择找到第 k 大数字时,只需要把数组此时的前 k 个数字返回即可。
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function (nums, k) {
// 统计出现次数
const map = {};
for (const n of nums) {
n in map || (map[n] = 0);
map[n]++;
}
const list = Object.entries(map);
quickSelect(list, k, 0, list.length - 1, function (item, pivot) {
return item[1] >= pivot[1];
});
return list.slice(0, k).map(el => el[0]);
};
/**
* 把 arr[r] 当成是 pivot
* 把大于等于 pivot 的数字放到左边
* 把小于 pivot 的数字放到右边
* @param {number[]} arr
* @param {number} l
* @param {number} r
*/
function partition(arr, l, r, comparator) {
if (typeof comparator != 'function') {
comparator = function (num, pivot) {
return num >= pivot;
};
}
let i = l;
for (let j = l; j < r; j++) {
if (comparator(arr[j], arr[r])) {
[arr[i], arr[j]] = [arr[j], arr[i]];
i++;
}
}
// 将 pivot 换到分界点
[arr[i], arr[r]] = [arr[r], arr[i]];
// 返回 pivot 的下标
return i;
}
/**
* 寻找第 k 大元素
* 如果 pivot 的下标刚好是 k - 1,那我们就找到了
* 如果下标大于 k - 1,那就在 [left, pivotIndex - 1] 这段找第 k 大元素
* 如果下标小于 k - 1,那就对 [pivotIndex + 1, right] 这段找第 k - pivotIndex + left - 1 大元素
* @param {number[]} list
* @param {number} left
* @param {number} right
* @param {number} k
* @param {function} comparator
*/
function quickSelect(list, k, left = 0, right = list.length - 1, comparator) {
if (left >= right) return list[left];
const pivotIndex = partition(list, left, right, comparator);
if (pivotIndex - left === k - 1) return list[pivotIndex];
else if (pivotIndex - left > k - 1)
return quickSelect(list, k, left, pivotIndex - 1, comparator);
else
return quickSelect(
list,
k - pivotIndex + left - 1,
pivotIndex + 1,
right,
comparator,
);
}
var topKFrequent = function(nums, k) {
let map = new Map(), arr = [...new Set(nums)]
nums.map((num) => {
if(map.has(num)) map.set(num, map.get(num)+1)
else map.set(num, 1)
})
// 如果元素数量小于等于 k
if(map.size <= k) {
return [...map.keys()]
}
return bucketSort(map, k)
};
// 桶排序
let bucketSort = (map, k) => {
let arr = [], res = []
map.forEach((value, key) => {
// 利用映射关系(出现频率作为下标)将数据分配到各个桶中
if(!arr[value]) {
arr[value] = [key]
} else {
arr[value].push(key)
}
})
// 倒序遍历获取出现频率最大的前k个数
for(let i = arr.length - 1;i >= 0 && res.length < k;i--){
if(arr[i]) {
res.push(...arr[i])
}
}
return res
}
思路: 哈希表记录出现次数,利用数组将次数与数值记录,再利用排序函数将数据进行排序,最后输出前K个。
func topKFrequent(nums []int, k int) []int {
hashmap := map[int]int{}
for _,x := range nums {
hashmap[x] ++
}
out := []data {}
for i,x := range hashmap{
out = append(out,data{num:i,time:x})
}
sort.Slice(out,func(i,j int) bool {
return out[i].time > out[j].time
})
ans := make([]int,k)
for i:=0;i<k;i++{
ans[i] = out[i].num
}
return ans
}
type data struct {
num int
time int
}
时间复杂度:nlogn 空间:n
class Solution { public int[] topKFrequent(int[] nums, int k) { / 出现频次前k高的元素,用桶排序的知识来求解, 我们把数出现的频次作为每个桶的标签,然后把出现相同频次的数字放入到对应的桶中, 而桶中的标签范围是根据数可能出现的最大次数决定的,接着初始化的时候标签就已经 按从小到大的顺序排好无需我们再次比较,直接到过来从标签最大的桶反向遍历每个桶, 从倒数第一个不为空的桶开始算,把里面的数取出来,就是频次出现最高的k个数了。 /
//定义一个hashmap来初始化每个数出现的频次,key是数值,value是频次
HashMap<Integer,Integer> hashMap = new HashMap<>();
//返回的结果集开辟空间
int[] result = new int[k];
for(int num : nums){
hashMap.put(num,hashMap.getOrDefault(num,0) + 1);
}
List<Integer>[] list = new ArrayList[nums.length + 1];
//让数字key出现的频次value作为桶的索引index
for(int num : hashMap.keySet()){
int i = hashMap.get(num);
//如果当前桶中还未建立对应的桶表我们就初始化一个
if(list[i] == null){
list[i] = new ArrayList<>();
}
list[i].add(num);
}
int i = 0, t , j;
//从频次最高的第一个不为空的桶开始反向取值
for(t = nums.length; t > 0; --t){
if(list[t] != null){
for(j = 0; j < list[t].size() && i < k; ++j){
result[i++] = list[t].get(j);
}
}
}
return result;
}
}
哈希表 + 桶排序
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function (nums, k) {
// 哈希
const map = new Map();
let maxSize = 0;
nums.forEach(num => {
if (!map.has(num)) {
map.set(num, 1);
maxSize = Math.max(1, maxSize);
} else {
const count = map.get(num) + 1;
map.set(num, count);
maxSize = Math.max(count, maxSize);
}
});
// 桶排
const bucket = new Array(maxSize + 1);
map.forEach((value, key) => {
if (bucket[value] === undefined) {
bucket[value] = [];
}
bucket[value].push(key);
})
// 答案
const res = [];
for (let i = maxSize; i >= 0 && res.length < k; i--) {
if (bucket[i] === undefined) {
continue;
}
res.push(...bucket[i]);
}
return res;
};
时间:O(N) 空间:O(N)
根据频率构建hashmap,而后采用heap, 在minheap中比较堆顶元素与新入队元素freq的大小,遍历heap出队
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i = 0; i < nums.length; i++){
map.put(nums[i],map.getOrDefault(nums[i],0)+1);
}
PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>(){
public int compare(int[] m, int[]n){
return m[1]-n[1];
}
});
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
int num = entry.getKey();
int freq = entry.getValue();
if(pq.size() == k){
if(pq.peek()[1]<freq){
pq.poll();
pq.offer(new int[]{num,freq});
}}
else{
pq.offer(new int[]{num,freq});
}
}
int[] res = new int[k];
int cnt = 0;
while(!pq.isEmpty()){
res[cnt] = pq.poll()[0];
cnt++;
}
return res;
}
}
class Solution { public int[] topKFrequent(int[] nums, int k) { Map<Integer, Integer> map = new HashMap<>(); for (int num : nums) { map.put(num, map.getOrDefault(num, 0) + 1); } return map.entrySet() .stream() .sorted((m1, m2) -> m2.getValue() - m1.getValue()) .limit(k) .mapToInt(Map.Entry::getKey) .toArray(); } }
先把每个数字和数字对应的次数 放到栈中保存 然后再创建一个 int[]的堆 int[] 第一个元素记录数字值 第二个元素记录改值出现的次数 然后挨个放到堆里面 堆的大小为K 判断当前的次数和堆顶的次数大小
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num,map.getOrDefault(num,0)+1);
}
//int[] 第一个元素记录数字值 第二个元素记录改值出现的次数
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
@Override
//从大到小排序
public int compare(int[] o1, int[] o2) {
return o1[1]-o2[1];
}
});
//
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
int num=entry.getKey(), count=entry.getValue();
if (queue.size()==k){
if (queue.peek()[1]<count){
//如果堆达到了k个 就比较当前的数组次数是否大于堆顶的数组的次数
queue.poll();
queue.offer(new int[]{num,count});
}
}else {
queue.offer(new int[]{num,count});
}
}
int[] ans=new int[k];
for (int i = 0; i <k ; i++) {
ans[i]=queue.poll()[0];
}
return ans;
}
}
复杂度分析 时间复杂度: O(nlog(k)) n为数组长度 放去哈希表需要O(n) 。 然后遍历 int[]数组 最多有N个,再对堆排序 时间为O(longk) ,总共为O(nlog(k))。 空间复杂度:O(n)为哈希表所需要的大小 O(k)为堆的大小 和最后返回答案的大小,所以总的复杂度为O(n)。
def topKFrequent(self, nums, k): """ :type nums: List[int] :type k: int :rtype: List[int] """ hashmap={} for i in nums: if i in hashmap: hashmap[i]=hashmap[i]+1 else: hashmap[i]=1 a1 = sorted(hashmap.items(),key = lambda x:x[1],reverse = True)#按照val值从大到小对哈希表排序 result=[] for key in a1: if k<=0: break result.append(key[0]) k=k-1 return result
Hash Map + 小顶堆
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for(int num : nums){
map.put(num, map.getOrDefault(num, 0) + 1);
}
Queue<int[]> pq = new PriorityQueue<>(
(o1, o2) -> o1[1] - o2[1]
);
for(Integer n : map.keySet()){
pq.offer(new int[]{n, map.get(n)});
if(pq.size() > k){
pq.poll();
}
}
int[] ans = new int[k];
for(int i = k - 1; i >= 0; i--){
ans[i] = pq.poll()[0];
}
return ans;
}
}
复杂度分析
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
count = collections.Counter(nums)
return [item[0] for item in count.most_common(k)]
进行堆排序,记录每个数字出现的次数,把数字和对应的出现次数放到堆中(小顶堆),如果堆已满(大小>=k)且当前数的次数比堆顶大,用当前元素替换堆顶元素,最后返回堆中的数字部分。
class Solution: def topKFrequent(self, nums: List[int], k: int) -> List[int]: count = collections.Counter(nums) heap = [] for key, val in count.items(): if len(heap) >= k: if val > heap[0][0]: heapq.heapreplace(heap, (val, key)) else: heapq.heappush(heap, (val, key)) return [item[1] for item in heap]
时间复杂度 O(NlogK)
空间复杂度 O(N)
思路:看见频率第一反应使用hash表求解
步骤:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap();
int[] ans = new int[k];
for(int i = 0;i<nums.length;i++){
if(map.containsKey(nums[i])){
map.put(nums[i],map.get(nums[i])+1);
}else{
map.put(nums[i],1);
}
}
//对map排序,使用value大小降序排序
List<Map.Entry<Integer,Integer>> list = new ArrayList(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<Integer,Integer>>(){
@Override
public int compare(Map.Entry<Integer,Integer> o1,Map.Entry<Integer,Integer> o2){
return o2.getValue() - o1.getValue();
}
});
for(int i = 0;i<k;i++){
ans[i] = list.get(i).getKey();
}
return ans;
}
}
时间:O(nlogn),瓶颈在排序;
空间:O(n),n为数组长度;
利用快速排序的思路,按频率从大到小快速排序,如果发现前半区间恰好就是top k的话,由于top k不要求有序,所以可以直接返回结果。
class Solution {
Map<Integer, Integer> freq;
public int[] topKFrequent(int[] nums, int k) {
freq = new HashMap<>();
for (int num : nums) {
freq.put(num, freq.getOrDefault(num, 0) + 1);
}
int[] numsNoDupe = new ArrayList<>(freq.keySet()).stream().mapToInt(i -> i).toArray();
return quickSelect(numsNoDupe, 0, numsNoDupe.length - 1, k);
}
private int[] quickSelect(int[] nums, int start, int end, int k) {
if (start >= end) {
return Arrays.copyOf(nums, k);
}
int l = start;
int r = end;
int pivot = freq.get(nums[l]);
while (l <= r) {
while (freq.get(nums[l]) > pivot) {
l++;
}
while (freq.get(nums[r]) < pivot) {
r--;
}
if (l <= r) {
int temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
l++;
r--;
}
}
// [0...r] [k] [l...n-1]
// [0...r][l...n-1]
if (r + 1 == k) {
return Arrays.copyOf(nums, k);
} else if (k > r) {
return quickSelect(nums, l, end, k);
} else {
return quickSelect(nums, start, r, k);
}
}
}
SC: O(N) 平均复杂度 TC: O(N) 哈希表
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
from collections import Counter
bucket = [[] for _ in range(len(nums)+1)]
count = Counter(nums)
for num, freq in count.items():
bucket[freq].append(num)
result = []
for freq in range(len(bucket)-1, -1, -1):
for element in bucket[freq]:
result.append(element)
if len(result)==k:
return result
time complexity: O(N) space complexity: O(N)
class Solution {
public int[] topKFrequent(int[] nums, int k) {
int[] res = new int[k];
// 统计次数
Map<Integer, Integer> counter = new HashMap<>();
for (int num : nums) {
counter.put(num, counter.getOrDefault(num, 0) + 1);
}
// 通过优先级队列,保持最高频次的数字 Integer[0]-次数 Integer[1]-数字
PriorityQueue<Integer[]> mostK = new PriorityQueue(k, new Comparator<Integer[]>() {
@Override
public int compare(Integer[] i1, Integer[] i2) {
return i1[0] - i2[0];
}
});
for (Integer key : counter.keySet()) {
Integer times = counter.get(key);
if (mostK.size() < k) {
mostK.offer(new Integer[]{times, key});
} else {
if (times > mostK.peek()[0]) {
mostK.poll();
mostK.offer(new Integer[]{times, key});
}
}
}
// 从优先级队列中取出相应的数字
int index = 0;
while (!mostK.isEmpty()) {
res[index++] = mostK.poll()[1];
}
return res;
}
}
val-freq map
minHeap
Time: O(nums.length) + O(number of entries) * logk + klogk
Space: O(number of entries) + O(k)
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> valFreq = new HashMap<>();
for (int num : nums) {
valFreq.put(num, valFreq.getOrDefault(num, 0) + 1);
}
PriorityQueue<Map.Entry<Integer, Integer>> minHeap = new PriorityQueue<>((a, b) -> (a.getValue() - b.getValue()));
for (Map.Entry<Integer, Integer> entry : valFreq.entrySet()) {
minHeap.offer(entry);
if (minHeap.size() > k) {
minHeap.poll();
}
}
int[] topK = new int[k];
int curIndex = 0;
while (!minHeap.isEmpty()) {
topK[curIndex++] = minHeap.poll().getKey();
}
return topK;
}
}
Python,先字典遍历求元素出现频率,然后 sorted排序 时间复杂度O(nlogn),空间复杂度O(n)
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
dict1 = {}
for i in range(len(nums)):
if nums[i] not in dict1:
dict1[nums[i]] = 1
else:
dict1[nums[i]] += 1
dict1_sorted_values = sorted(dict1.items(),key = lambda x:x[1],reverse = True)
res = []
for i in range(k):
res.append(dict1_sorted_values[i][0])
return res
347. 前 K 个高频元素
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/top-k-frequent-elements/
前置知识
题目描述
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]
示例 2:
输入: nums = [1], k = 1 输出: [1]
提示:
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/top-k-frequent-elements 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。