Top K Frequent Words

You are given a list of lowercase words words and an integer k. Return the k words that occur most often, as a list without repeats.

The result must be ordered from the most frequent word to the least frequent. When two words occur the same number of times, the one that comes first in alphabetical (lexicographic) order goes first; for example "ant" comes before "ants", which comes before "bee". This tie-breaking rule also decides which words make the cut when several share the k-th highest count.

Example 1

Input: words = ["apple","kiwi","apple","fig","kiwi","apple"], k = 2 Output: ["apple","kiwi"] Why: "apple" occurs 3 times and "kiwi" twice, so they are the top two.

Example 2

Input: words = ["sun","moon","star","moon","sun","comet"], k = 3 Output: ["moon","sun","comet"] Why: "moon" and "sun" both occur twice and "moon" sorts first. Among the words seen once, "comet" beats "star" alphabetically.

Example 3

Input: words = ["b","a","c"], k = 3 Output: ["a","b","c"] Why: Every word occurs once, so the answer is all three in alphabetical order.

Constraints

  • 1 <= words.length <= 104
  • 1 <= words[i].length <= 10, lowercase English letters only
  • 1 <= k <= number of distinct words

Pattern Path · Heaps & Top-K · problem 104 of 169

Start by counting how many times each word appears. Which data structure makes that a single pass?
Once you have the counts, the task is to order distinct words by two keys: count (high to low), then the word itself (A to Z).
Sorting all distinct words by (-count, word) and taking the first k works. For large inputs with small k, a heap of size k avoids sorting everything.
Target: O(n + u log u) time, O(u) extra space.

Start simple

For each of the k answer slots, scan every distinct word and recount its occurrences to pick the best remaining one: O(k·u·n) time for u distinct words.

The key idea

Two steps: count, then rank.

A hash map from word to count, built in one pass over the input, gives every frequency in O(n) time. The ranking rule is a composite key: higher count first, and among equal counts, the alphabetically smaller word first. Encoding it as the tuple (-count, word) lets an ordinary ascending sort do both at once, because tuples compare their first field and fall back to the second on ties. Take the first k words of the sorted list.

Sorting the u distinct words costs O(u log u). If u is large and k small, keep a heap of only k candidates instead, ordered so that the worst candidate (lowest count, then alphabetically last) sits on top and is evicted first. That brings ranking down to O(u log k), and you sort the k survivors at the end. Getting the tie-break direction right inside the heap is the subtle part, which is why the sort-based version is a good first answer.

Complexity

  • Time: O(n + u log u)
  • Space: O(u)

Python

from collections import Counter


class Solution:
    def topKFrequent(self, words: List[str], k: int) -> List[str]:
        counts = Counter(words)
        # Most frequent first; equal counts fall back to alphabetical order.
        ranked = sorted(counts, key=lambda word: (-counts[word], word))
        return ranked[:k]

JavaScript

var topKFrequent = function(words, k) {
  const counts = new Map();
  for (const word of words) counts.set(word, (counts.get(word) || 0) + 1);

  // Most frequent first; equal counts fall back to alphabetical order.
  const ranked = [...counts.keys()].sort((a, b) => {
    const diff = counts.get(b) - counts.get(a);
    if (diff !== 0) return diff;
    return a < b ? -1 : a > b ? 1 : 0;
  });
  return ranked.slice(0, k);
};

What the interviewer is checking

The interviewer is testing hash-map counting plus a custom ordering, and whether you can upgrade to a size-k heap and get the inverted tie-break right inside it.

Mistakes to avoid

  • Breaking ties in the wrong direction (reverse alphabetical), especially inside a min-heap.
  • Returning the k words in heap order instead of sorted order.
  • Comparing strings with a locale-aware function, which may not match plain character order.

Follow-ups to expect

  • Achieve O(n log k). (Size-k heap with inverted tie-break.)
  • Words arrive as an endless stream. (Count-min sketch plus heap.)
  • Linear time when counts are bounded. (Bucket sort by frequency.)

In real software

Search engines and analytics dashboards report trending queries or top error messages this way, and autocomplete ranks suggestions by frequency with alphabetical tie-breaking.

Practice next

Next Post Previous Post
No Comment
Add Comment
comment url