Opening the reading…
Opening the reading…
SORTING › BUCKET SORT
Open — the attempt gate is not wired up yet
This editorial is meant to unlock after you have run the problem at least once, with the worked solution behind one further deliberate click. That needs per-learner unlock state nothing stores today, so for now the whole article is open.
Try it yourself first →The answer is determined entirely by how often each distinct value appears. Count those appearances first, then rank the distinct values by their counts. A value appearing five times must be considered before one appearing twice, regardless of the values themselves or the order in which they occur in nums.
The frequencies have a useful bounded range: no value can appear more than nums.size times. That means you can create bucket f for every possible frequency f, put each value into the bucket matching its count, and scan from the largest bucket downward. The first k values encountered are exactly the k most frequent values; ties cannot make the answer ambiguous because the problem guarantees a unique answer.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n) | Counting examines all n input elements once, placing distinct values examines each distinct value once, and the bucket scan examines at most n + 1 frequency positions. The total is linear because these passes are separate and no value is repeatedly compared with every other value. |
| Space | O(n) extra | The frequency map, the n + 1 bucket positions, and the references to distinct values together use O(n) working space in the worst case, such as when every input value is different. The returned result is required output and is excluded from the extra-space bound. |
#include <unordered_map>
#include <vector>
using namespace std;
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> freq;
for (int x : nums) {
++freq[x];
}
int n = static_cast<int>(nums.size());
vector<vector<int>> buckets(n + 1);
for (const auto& entry : freq) {
int value = entry.first;
int count = entry.second;
buckets[count].push_back(value);
}
vector<int> result;
for (int count = n; count >= 1 && static_cast<int>(result.size()) < k; --count) {
for (int value : buckets[count]) {
result.push_back(value);
if (static_cast<int>(result.size()) == k) {
break;
}
}
}
return result;
}
};The bucket index is the central line of the solution: buckets[count]. A value is inserted once after its final count is known, so the later scan never needs to compare two values directly. The second stopping condition matters as well. It prevents the code from collecting extra values from the same bucket when several values share the frequency at which the kth answer is found.
A min-heap gives another natural solution. First count frequencies, then keep only the best k values seen so far. The heap root is the currently weakest selected value, so whenever a new value is stronger than that root, remove the root and insert the new value. This is not an optimisation over buckets in asymptotic time, but it uses O(k) selection storage instead of storing frequency buckets for every possible count.
#include <queue>
#include <unordered_map>
#include <vector>
using namespace std;
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> freq;
for (int x : nums) {
++freq[x];
}
using Entry = pair<int, int>;
priority_queue<Entry, vector<Entry>, greater<Entry>> minHeap;
for (const auto& entry : freq) {
int value = entry.first;
int count = entry.second;
minHeap.push({count, value});
if (static_cast<int>(minHeap.size()) > k) {
minHeap.pop();
}
}
vector<int> result;
while (!minHeap.empty()) {
result.push_back(minHeap.top().second);
minHeap.pop();
}
return result;
}
};| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n + u log k) | Counting costs O(n). Each of the u distinct values enters the heap once and may cause one removal, with each heap operation costing O(log k) because the heap never grows beyond k + 1 entries. |
| Space | O(u + k) extra | The frequency map stores u distinct values and the heap stores at most k values. The returned result is required output and is excluded from this bound. Since u can equal n, the worst case is O(n + k), which is O(n). |