Skip to main content

Top K Frequent Elements

How to count frequency first and then choose only the top K efficiently.

Given an integer array nums and an integer k, return the k most frequent elements.

In the original problem, any order is usually accepted. In the SeniorPath playground, return them in descending frequency order to keep comparison deterministic.

Example:

Input:  nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

What to notice before coding

Common mistakes

Step 1 - Split the problem into two parts

Many people try to answer directly:

  • who are the most frequent elements?

But before that there is a smaller question:

  • what is the frequency of each value?

Without that step, you cannot compare anything.

Step 2 - Write the most direct baseline

The natural baseline is:

  • count frequency with a Hash Map
  • turn it into a list of pairs
  • sort by frequency
  • take the first K

It works well.

The extra cost is sorting everything.

Step 3 - Ask what really matters

The problem does not ask for the whole list ordered.

It asks for:

  • only the K most frequent elements

That creates room for a better selection strategy.

Step 4 - Use frequency buckets

The maximum frequency never exceeds nums.length.

So you can create buckets where:

  • the index represents the frequency
  • each bucket stores the values with that frequency

Then you just walk from the highest bucket down.

If frequency were not naturally bounded, a heap would be a common middle ground between full sort and buckets.

The interactive editor needs JavaScript. You can still read the prompt and copy the starter code below.

Starter code

export function topKFrequent(nums: number[], k: number): number[] {
  // your solution here
  return []
}
solution.ts
Stuck? Hints available.

Haven't solved it yet?

Viewing the solution now may reduce learning. It's worth trying a bit more.

Open the reference solution

Without JavaScript, the reference solution is shown inline instead of in a dialog.

Solution

Final complexity

Time: O(n)

Space: O(n)

Solution 1 - Count with a Hash Map and sort all pairs

Good baseline because it makes both phases explicit.

export function topKFrequent(nums: number[], k: number): number[] {
  const counts = new Map<number, number>()

  for (const num of nums) {
    counts.set(num, (counts.get(num) ?? 0) + 1)
  }

  return [...counts.entries()]
    .sort((a, b) => b[1] - a[1] || a[0] - b[0])
    .slice(0, k)
    .map(([value]) => value)
}

It works. But you sort every candidate even though you only need a few of them.

Solution 2 - Frequency buckets after the Hash Map instead of a heap

Now selection happens without a global sort.

export function topKFrequent(nums: number[], k: number): number[] {
  const counts = new Map<number, number>()

  for (const num of nums) {
    counts.set(num, (counts.get(num) ?? 0) + 1)
  }

  const buckets = Array.from({ length: nums.length + 1 }, () => [])

  for (const [value, frequency] of counts.entries()) {
    buckets[frequency].push(value)
  }

  const result: number[] = []

  for (let frequency = buckets.length - 1; frequency >= 0 && result.length < k; frequency -= 1) {
    for (const value of buckets[frequency]) {
      result.push(value)

      if (result.length === k) {
        break
      }
    }
  }

  return result
}

The strong idea here is realizing that frequency itself can become an index.

That is why this beats a heap here: the problem gives you a small bounded range for frequency.

What to say in the interview

A strong short explanation would be:

First I count the frequency of each value with a Hash Map. The baseline would sort all (value, frequency) pairs and take the top K. The better version uses buckets indexed by frequency, because the maximum frequency cannot exceed n. Then I walk from the highest bucket down until I collect K elements in O(n).

That shows that you:

  • separated counting from selection
  • justified why full sorting was not required
  • explained the structure of the solution clearly

When this pattern shows up again

The same pattern comes back when you need to:

  • count frequency before deciding
  • select top K
    • discuss the trade-off between sort, heap, and buckets
  • turn a bounded attribute into an index

The point is not memorizing topKFrequent.

The point is learning to separate “measure” from “choose”.

Next challenge Min Stack Previous challenge Binary Tree Level Order Traversal

Related challenges

Related articles