diff --git a/solution/0300-0399/0347.Top K Frequent Elements/README.md b/solution/0300-0399/0347.Top K Frequent Elements/README.md index b8421d7368cba..0a21210a0545e 100644 --- a/solution/0300-0399/0347.Top K Frequent Elements/README.md +++ b/solution/0300-0399/0347.Top K Frequent Elements/README.md @@ -62,9 +62,13 @@ tags: ### 方法一:哈希表 + 优先队列(小根堆) -使用哈希表统计每个元素出现的次数,然后使用优先队列(小根堆)维护前 $k$ 个出现次数最多的元素。 +我们可以使用一个哈希表 $\text{cnt}$ 统计每个元素出现的次数,然后使用一个小根堆(优先队列)来保存前 $k$ 个高频元素。 -时间复杂度 $O(n\log k)$。 +我们首先遍历一遍数组,统计每个元素出现的次数,然后遍历哈希表,将元素和出现次数存入小根堆中。如果小根堆的大小超过了 $k$,我们就将堆顶元素弹出,保证堆的大小始终为 $k$。 + +最后,我们将小根堆中的元素依次弹出,放入结果数组中即可。 + +时间复杂度 $O(n \times \log k)$,空间复杂度 $O(k)$。其中 $n$ 是数组的长度。 @@ -74,7 +78,7 @@ tags: class Solution: def topKFrequent(self, nums: List[int], k: int) -> List[int]: cnt = Counter(nums) - return [v[0] for v in cnt.most_common(k)] + return [x for x, _ in cnt.most_common(k)] ``` #### Java @@ -82,16 +86,19 @@ class Solution: ```java class Solution { public int[] topKFrequent(int[] nums, int k) { - Map frequency = Arrays.stream(nums).boxed().collect( - Collectors.groupingBy(Function.identity(), Collectors.counting())); - Queue> queue = new PriorityQueue<>(Map.Entry.comparingByValue()); - for (var entry : frequency.entrySet()) { - queue.offer(entry); - if (queue.size() > k) { - queue.poll(); + Map cnt = new HashMap<>(); + for (int x : nums) { + cnt.merge(x, 1, Integer::sum); + } + PriorityQueue> pq + = new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue)); + for (var e : cnt.entrySet()) { + pq.offer(e); + if (pq.size() > k) { + pq.poll(); } } - return queue.stream().mapToInt(Map.Entry::getKey).toArray(); + return pq.stream().mapToInt(Map.Entry::getKey).toArray(); } } ``` @@ -99,23 +106,24 @@ class Solution { #### C++ ```cpp -using pii = pair; - class Solution { public: vector topKFrequent(vector& nums, int k) { unordered_map cnt; - for (int v : nums) ++cnt[v]; + using pii = pair; + for (int x : nums) { + ++cnt[x]; + } priority_queue, greater> pq; - for (auto& [num, freq] : cnt) { - pq.push({freq, num}); + for (auto& [x, c] : cnt) { + pq.push({c, x}); if (pq.size() > k) { pq.pop(); } } - vector ans(k); - for (int i = 0; i < k; ++i) { - ans[i] = pq.top().second; + vector ans; + while (!pq.empty()) { + ans.push_back(pq.top().second); pq.pop(); } return ans; @@ -128,19 +136,19 @@ public: ```go func topKFrequent(nums []int, k int) []int { cnt := map[int]int{} - for _, v := range nums { - cnt[v]++ + for _, x := range nums { + cnt[x]++ } - h := hp{} - for v, freq := range cnt { - heap.Push(&h, pair{v, freq}) - if len(h) > k { - heap.Pop(&h) + pq := hp{} + for x, c := range cnt { + heap.Push(&pq, pair{x, c}) + if pq.Len() > k { + heap.Pop(&pq) } } ans := make([]int, k) - for i := range ans { - ans[i] = heap.Pop(&h).(pair).v + for i := 0; i < k; i++ { + ans[i] = heap.Pop(&pq).(pair).v } return ans } @@ -159,124 +167,42 @@ func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; ```ts function topKFrequent(nums: number[], k: number): number[] { - let hashMap = new Map(); - for (let num of nums) { - hashMap.set(num, (hashMap.get(num) || 0) + 1); + const cnt = new Map(); + for (const x of nums) { + cnt.set(x, (cnt.get(x) ?? 0) + 1); } - let list = [...hashMap]; - list.sort((a, b) => b[1] - a[1]); - let ans = []; - for (let i = 0; i < k; i++) { - ans.push(list[i][0]); + const pq = new MinPriorityQueue(); + for (const [x, c] of cnt) { + pq.enqueue(x, c); + if (pq.size() > k) { + pq.dequeue(); + } } - return ans; + return pq.toArray().map(x => x.element); } ``` #### Rust ```rust -use std::collections::HashMap; +use std::cmp::Reverse; +use std::collections::{BinaryHeap, HashMap}; + impl Solution { pub fn top_k_frequent(nums: Vec, k: i32) -> Vec { - let mut map = HashMap::new(); - let mut max_count = 0; - for &num in nums.iter() { - let val = map.get(&num).unwrap_or(&0) + 1; - map.insert(num, val); - max_count = max_count.max(val); + let mut cnt = HashMap::new(); + for x in nums { + *cnt.entry(x).or_insert(0) += 1; } - let mut k = k as usize; - let mut res = vec![0; k]; - while k > 0 { - let mut next = 0; - for key in map.keys() { - let val = map[key]; - if val == max_count { - res[k - 1] = *key; - k -= 1; - } else if val < max_count { - next = next.max(val); - } - } - max_count = next; - } - res - } -} -``` - - - - - - - -### 方法二 - - - -#### Python3 - -```python -class Solution: - def topKFrequent(self, nums: List[int], k: int) -> List[int]: - cnt = Counter(nums) - hp = [] - for num, freq in cnt.items(): - heappush(hp, (freq, num)) - if len(hp) > k: - heappop(hp) - return [v[1] for v in hp] -``` - -#### Java - -```java -class Solution { - public int[] topKFrequent(int[] nums, int k) { - Map cnt = new HashMap<>(); - for (int v : nums) { - cnt.put(v, cnt.getOrDefault(v, 0) + 1); - } - PriorityQueue pq = new PriorityQueue<>((a, b) -> a[1] - b[1]); - for (var e : cnt.entrySet()) { - pq.offer(new int[] {e.getKey(), e.getValue()}); - if (pq.size() > k) { - pq.poll(); - } - } - int[] ans = new int[k]; - for (int i = 0; i < k; ++i) { - ans[i] = pq.poll()[0]; - } - return ans; - } -} -``` - -#### TypeScript - -```ts -function topKFrequent(nums: number[], k: number): number[] { - const map = new Map(); - let maxCount = 0; - for (const num of nums) { - map.set(num, (map.get(num) ?? 0) + 1); - maxCount = Math.max(maxCount, map.get(num)); - } - - const res = []; - while (k > 0) { - for (const key of map.keys()) { - if (map.get(key) === maxCount) { - res.push(key); - k--; + let mut pq = BinaryHeap::with_capacity(k as usize); + for (&x, &c) in cnt.iter() { + pq.push(Reverse((c, x))); + if pq.len() > k as usize { + pq.pop(); } } - maxCount--; + pq.into_iter().map(|Reverse((_, x))| x).collect() } - return res; } ``` diff --git a/solution/0300-0399/0347.Top K Frequent Elements/README_EN.md b/solution/0300-0399/0347.Top K Frequent Elements/README_EN.md index 11e80c6b8e2d5..c72b5148eb7d4 100644 --- a/solution/0300-0399/0347.Top K Frequent Elements/README_EN.md +++ b/solution/0300-0399/0347.Top K Frequent Elements/README_EN.md @@ -52,7 +52,15 @@ tags: -### Solution 1 +### Solution 1: Hash Table + Priority Queue (Min Heap) + +We can use a hash table $\text{cnt}$ to count the occurrence of each element, and then use a min heap (priority queue) to store the top $k$ frequent elements. + +First, we traverse the array once to count the occurrence of each element. Then, we iterate through the hash table, storing each element and its count into the min heap. If the size of the min heap exceeds $k$, we pop the top element of the heap to ensure the heap size is always $k$. + +Finally, we pop the elements from the min heap one by one and place them into the result array. + +The time complexity is $O(n \log k)$, and the space complexity is $O(k)$. Here, $n$ is the length of the array. @@ -62,7 +70,7 @@ tags: class Solution: def topKFrequent(self, nums: List[int], k: int) -> List[int]: cnt = Counter(nums) - return [v[0] for v in cnt.most_common(k)] + return [x for x, _ in cnt.most_common(k)] ``` #### Java @@ -70,16 +78,19 @@ class Solution: ```java class Solution { public int[] topKFrequent(int[] nums, int k) { - Map frequency = Arrays.stream(nums).boxed().collect( - Collectors.groupingBy(Function.identity(), Collectors.counting())); - Queue> queue = new PriorityQueue<>(Map.Entry.comparingByValue()); - for (var entry : frequency.entrySet()) { - queue.offer(entry); - if (queue.size() > k) { - queue.poll(); + Map cnt = new HashMap<>(); + for (int x : nums) { + cnt.merge(x, 1, Integer::sum); + } + PriorityQueue> pq + = new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue)); + for (var e : cnt.entrySet()) { + pq.offer(e); + if (pq.size() > k) { + pq.poll(); } } - return queue.stream().mapToInt(Map.Entry::getKey).toArray(); + return pq.stream().mapToInt(Map.Entry::getKey).toArray(); } } ``` @@ -87,23 +98,24 @@ class Solution { #### C++ ```cpp -using pii = pair; - class Solution { public: vector topKFrequent(vector& nums, int k) { unordered_map cnt; - for (int v : nums) ++cnt[v]; + using pii = pair; + for (int x : nums) { + ++cnt[x]; + } priority_queue, greater> pq; - for (auto& [num, freq] : cnt) { - pq.push({freq, num}); + for (auto& [x, c] : cnt) { + pq.push({c, x}); if (pq.size() > k) { pq.pop(); } } - vector ans(k); - for (int i = 0; i < k; ++i) { - ans[i] = pq.top().second; + vector ans; + while (!pq.empty()) { + ans.push_back(pq.top().second); pq.pop(); } return ans; @@ -116,19 +128,19 @@ public: ```go func topKFrequent(nums []int, k int) []int { cnt := map[int]int{} - for _, v := range nums { - cnt[v]++ + for _, x := range nums { + cnt[x]++ } - h := hp{} - for v, freq := range cnt { - heap.Push(&h, pair{v, freq}) - if len(h) > k { - heap.Pop(&h) + pq := hp{} + for x, c := range cnt { + heap.Push(&pq, pair{x, c}) + if pq.Len() > k { + heap.Pop(&pq) } } ans := make([]int, k) - for i := range ans { - ans[i] = heap.Pop(&h).(pair).v + for i := 0; i < k; i++ { + ans[i] = heap.Pop(&pq).(pair).v } return ans } @@ -147,124 +159,42 @@ func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; ```ts function topKFrequent(nums: number[], k: number): number[] { - let hashMap = new Map(); - for (let num of nums) { - hashMap.set(num, (hashMap.get(num) || 0) + 1); + const cnt = new Map(); + for (const x of nums) { + cnt.set(x, (cnt.get(x) ?? 0) + 1); } - let list = [...hashMap]; - list.sort((a, b) => b[1] - a[1]); - let ans = []; - for (let i = 0; i < k; i++) { - ans.push(list[i][0]); + const pq = new MinPriorityQueue(); + for (const [x, c] of cnt) { + pq.enqueue(x, c); + if (pq.size() > k) { + pq.dequeue(); + } } - return ans; + return pq.toArray().map(x => x.element); } ``` #### Rust ```rust -use std::collections::HashMap; +use std::cmp::Reverse; +use std::collections::{BinaryHeap, HashMap}; + impl Solution { pub fn top_k_frequent(nums: Vec, k: i32) -> Vec { - let mut map = HashMap::new(); - let mut max_count = 0; - for &num in nums.iter() { - let val = map.get(&num).unwrap_or(&0) + 1; - map.insert(num, val); - max_count = max_count.max(val); - } - let mut k = k as usize; - let mut res = vec![0; k]; - while k > 0 { - let mut next = 0; - for key in map.keys() { - let val = map[key]; - if val == max_count { - res[k - 1] = *key; - k -= 1; - } else if val < max_count { - next = next.max(val); - } - } - max_count = next; + let mut cnt = HashMap::new(); + for x in nums { + *cnt.entry(x).or_insert(0) += 1; } - res - } -} -``` - - - - - - - -### Solution 2 - - - -#### Python3 - -```python -class Solution: - def topKFrequent(self, nums: List[int], k: int) -> List[int]: - cnt = Counter(nums) - hp = [] - for num, freq in cnt.items(): - heappush(hp, (freq, num)) - if len(hp) > k: - heappop(hp) - return [v[1] for v in hp] -``` - -#### Java - -```java -class Solution { - public int[] topKFrequent(int[] nums, int k) { - Map cnt = new HashMap<>(); - for (int v : nums) { - cnt.put(v, cnt.getOrDefault(v, 0) + 1); - } - PriorityQueue pq = new PriorityQueue<>((a, b) -> a[1] - b[1]); - for (var e : cnt.entrySet()) { - pq.offer(new int[] {e.getKey(), e.getValue()}); - if (pq.size() > k) { - pq.poll(); - } - } - int[] ans = new int[k]; - for (int i = 0; i < k; ++i) { - ans[i] = pq.poll()[0]; - } - return ans; - } -} -``` - -#### TypeScript - -```ts -function topKFrequent(nums: number[], k: number): number[] { - const map = new Map(); - let maxCount = 0; - for (const num of nums) { - map.set(num, (map.get(num) ?? 0) + 1); - maxCount = Math.max(maxCount, map.get(num)); - } - - const res = []; - while (k > 0) { - for (const key of map.keys()) { - if (map.get(key) === maxCount) { - res.push(key); - k--; + let mut pq = BinaryHeap::with_capacity(k as usize); + for (&x, &c) in cnt.iter() { + pq.push(Reverse((c, x))); + if pq.len() > k as usize { + pq.pop(); } } - maxCount--; + pq.into_iter().map(|Reverse((_, x))| x).collect() } - return res; } ``` diff --git a/solution/0300-0399/0347.Top K Frequent Elements/Solution.cpp b/solution/0300-0399/0347.Top K Frequent Elements/Solution.cpp index 6c9ddd0f1f3e6..dd6b67bdee2aa 100644 --- a/solution/0300-0399/0347.Top K Frequent Elements/Solution.cpp +++ b/solution/0300-0399/0347.Top K Frequent Elements/Solution.cpp @@ -1,22 +1,23 @@ -using pii = pair; - class Solution { public: vector topKFrequent(vector& nums, int k) { unordered_map cnt; - for (int v : nums) ++cnt[v]; + using pii = pair; + for (int x : nums) { + ++cnt[x]; + } priority_queue, greater> pq; - for (auto& [num, freq] : cnt) { - pq.push({freq, num}); + for (auto& [x, c] : cnt) { + pq.push({c, x}); if (pq.size() > k) { pq.pop(); } } - vector ans(k); - for (int i = 0; i < k; ++i) { - ans[i] = pq.top().second; + vector ans; + while (!pq.empty()) { + ans.push_back(pq.top().second); pq.pop(); } return ans; } -}; \ No newline at end of file +}; diff --git a/solution/0300-0399/0347.Top K Frequent Elements/Solution.go b/solution/0300-0399/0347.Top K Frequent Elements/Solution.go index 4df836e6d8670..7cf9043a523d3 100644 --- a/solution/0300-0399/0347.Top K Frequent Elements/Solution.go +++ b/solution/0300-0399/0347.Top K Frequent Elements/Solution.go @@ -1,18 +1,18 @@ func topKFrequent(nums []int, k int) []int { cnt := map[int]int{} - for _, v := range nums { - cnt[v]++ + for _, x := range nums { + cnt[x]++ } - h := hp{} - for v, freq := range cnt { - heap.Push(&h, pair{v, freq}) - if len(h) > k { - heap.Pop(&h) + pq := hp{} + for x, c := range cnt { + heap.Push(&pq, pair{x, c}) + if pq.Len() > k { + heap.Pop(&pq) } } ans := make([]int, k) - for i := range ans { - ans[i] = heap.Pop(&h).(pair).v + for i := 0; i < k; i++ { + ans[i] = heap.Pop(&pq).(pair).v } return ans } @@ -24,4 +24,4 @@ func (h hp) Len() int { return len(h) } func (h hp) Less(i, j int) bool { return h[i].cnt < h[j].cnt } func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } func (h *hp) Push(v any) { *h = append(*h, v.(pair)) } -func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v } \ No newline at end of file +func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v } diff --git a/solution/0300-0399/0347.Top K Frequent Elements/Solution.java b/solution/0300-0399/0347.Top K Frequent Elements/Solution.java index 2dd78e1c6fdbc..0161a90bf1e76 100644 --- a/solution/0300-0399/0347.Top K Frequent Elements/Solution.java +++ b/solution/0300-0399/0347.Top K Frequent Elements/Solution.java @@ -1,14 +1,17 @@ class Solution { public int[] topKFrequent(int[] nums, int k) { - Map frequency = Arrays.stream(nums).boxed().collect( - Collectors.groupingBy(Function.identity(), Collectors.counting())); - Queue> queue = new PriorityQueue<>(Map.Entry.comparingByValue()); - for (var entry : frequency.entrySet()) { - queue.offer(entry); - if (queue.size() > k) { - queue.poll(); + Map cnt = new HashMap<>(); + for (int x : nums) { + cnt.merge(x, 1, Integer::sum); + } + PriorityQueue> pq + = new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue)); + for (var e : cnt.entrySet()) { + pq.offer(e); + if (pq.size() > k) { + pq.poll(); } } - return queue.stream().mapToInt(Map.Entry::getKey).toArray(); + return pq.stream().mapToInt(Map.Entry::getKey).toArray(); } -} \ No newline at end of file +} diff --git a/solution/0300-0399/0347.Top K Frequent Elements/Solution.py b/solution/0300-0399/0347.Top K Frequent Elements/Solution.py index bb2e27754c5f0..2f1eac588f73c 100644 --- a/solution/0300-0399/0347.Top K Frequent Elements/Solution.py +++ b/solution/0300-0399/0347.Top K Frequent Elements/Solution.py @@ -1,4 +1,4 @@ class Solution: def topKFrequent(self, nums: List[int], k: int) -> List[int]: cnt = Counter(nums) - return [v[0] for v in cnt.most_common(k)] + return [x for x, _ in cnt.most_common(k)] diff --git a/solution/0300-0399/0347.Top K Frequent Elements/Solution.rs b/solution/0300-0399/0347.Top K Frequent Elements/Solution.rs index 1de7f5007bb07..9bed087c179ec 100644 --- a/solution/0300-0399/0347.Top K Frequent Elements/Solution.rs +++ b/solution/0300-0399/0347.Top K Frequent Elements/Solution.rs @@ -1,28 +1,19 @@ -use std::collections::HashMap; +use std::cmp::Reverse; +use std::collections::{BinaryHeap, HashMap}; + impl Solution { pub fn top_k_frequent(nums: Vec, k: i32) -> Vec { - let mut map = HashMap::new(); - let mut max_count = 0; - for &num in nums.iter() { - let val = map.get(&num).unwrap_or(&0) + 1; - map.insert(num, val); - max_count = max_count.max(val); + let mut cnt = HashMap::new(); + for x in nums { + *cnt.entry(x).or_insert(0) += 1; } - let mut k = k as usize; - let mut res = vec![0; k]; - while k > 0 { - let mut next = 0; - for key in map.keys() { - let val = map[key]; - if val == max_count { - res[k - 1] = *key; - k -= 1; - } else if val < max_count { - next = next.max(val); - } + let mut pq = BinaryHeap::with_capacity(k as usize); + for (&x, &c) in cnt.iter() { + pq.push(Reverse((c, x))); + if pq.len() > k as usize { + pq.pop(); } - max_count = next; } - res + pq.into_iter().map(|Reverse((_, x))| x).collect() } } diff --git a/solution/0300-0399/0347.Top K Frequent Elements/Solution.ts b/solution/0300-0399/0347.Top K Frequent Elements/Solution.ts index 9f20a96a72ebf..5b647b5a01d9c 100644 --- a/solution/0300-0399/0347.Top K Frequent Elements/Solution.ts +++ b/solution/0300-0399/0347.Top K Frequent Elements/Solution.ts @@ -1,13 +1,14 @@ function topKFrequent(nums: number[], k: number): number[] { - let hashMap = new Map(); - for (let num of nums) { - hashMap.set(num, (hashMap.get(num) || 0) + 1); + const cnt = new Map(); + for (const x of nums) { + cnt.set(x, (cnt.get(x) ?? 0) + 1); } - let list = [...hashMap]; - list.sort((a, b) => b[1] - a[1]); - let ans = []; - for (let i = 0; i < k; i++) { - ans.push(list[i][0]); + const pq = new MinPriorityQueue(); + for (const [x, c] of cnt) { + pq.enqueue(x, c); + if (pq.size() > k) { + pq.dequeue(); + } } - return ans; + return pq.toArray().map(x => x.element); } diff --git a/solution/0300-0399/0347.Top K Frequent Elements/Solution2.java b/solution/0300-0399/0347.Top K Frequent Elements/Solution2.java deleted file mode 100644 index 50579ba0ce6b6..0000000000000 --- a/solution/0300-0399/0347.Top K Frequent Elements/Solution2.java +++ /dev/null @@ -1,20 +0,0 @@ -class Solution { - public int[] topKFrequent(int[] nums, int k) { - Map cnt = new HashMap<>(); - for (int v : nums) { - cnt.put(v, cnt.getOrDefault(v, 0) + 1); - } - PriorityQueue pq = new PriorityQueue<>((a, b) -> a[1] - b[1]); - for (var e : cnt.entrySet()) { - pq.offer(new int[] {e.getKey(), e.getValue()}); - if (pq.size() > k) { - pq.poll(); - } - } - int[] ans = new int[k]; - for (int i = 0; i < k; ++i) { - ans[i] = pq.poll()[0]; - } - return ans; - } -} \ No newline at end of file diff --git a/solution/0300-0399/0347.Top K Frequent Elements/Solution2.py b/solution/0300-0399/0347.Top K Frequent Elements/Solution2.py deleted file mode 100644 index 37e7fac77f36d..0000000000000 --- a/solution/0300-0399/0347.Top K Frequent Elements/Solution2.py +++ /dev/null @@ -1,9 +0,0 @@ -class Solution: - def topKFrequent(self, nums: List[int], k: int) -> List[int]: - cnt = Counter(nums) - hp = [] - for num, freq in cnt.items(): - heappush(hp, (freq, num)) - if len(hp) > k: - heappop(hp) - return [v[1] for v in hp] diff --git a/solution/0300-0399/0347.Top K Frequent Elements/Solution2.ts b/solution/0300-0399/0347.Top K Frequent Elements/Solution2.ts deleted file mode 100644 index 9001644391a42..0000000000000 --- a/solution/0300-0399/0347.Top K Frequent Elements/Solution2.ts +++ /dev/null @@ -1,20 +0,0 @@ -function topKFrequent(nums: number[], k: number): number[] { - const map = new Map(); - let maxCount = 0; - for (const num of nums) { - map.set(num, (map.get(num) ?? 0) + 1); - maxCount = Math.max(maxCount, map.get(num)); - } - - const res = []; - while (k > 0) { - for (const key of map.keys()) { - if (map.get(key) === maxCount) { - res.push(key); - k--; - } - } - maxCount--; - } - return res; -}