LeetCode #692 Medium

Top K Frequent Words

Return the k most frequent words, breaking ties lexicographically.

heaphash-mapsortingstring
Open on LeetCode ↗
02

Intuition

💡

Ordering purely by frequency looks sufficient, but it isn't: ties must break LEXICOGRAPHICALLY, and the two orderings actually run in OPPOSITE directions. The final answer wants frequency descending but the word ascending. In a fixed-size min-heap that means the comparator has to invert the frequency comparison to keep evicting the worst entry, while leaving the word comparison alone to keep tie-breaking correctly, and mixing that up is exactly where people go wrong. Count first, then compare pairs of (word, count) with frequency as the primary key and the word as the secondary key, always in that asymmetric direction.

03

Approach

1

Count occurrences

Build a frequency map from word to count in one pass, remembering first-seen order only for readability, since the map itself is what the ranking reads from.

2

Maintain a bounded min-heap of size k

Push each distinct word with its count into a heap ordered so the WORST candidate sits at the top: lowest frequency, and on a tied frequency, the lexicographically LARGER word (since it should rank worse). Whenever the heap exceeds k, evict that top entry.

3

Read out in the opposite order

Once every word has been considered, sort the surviving heap entries by frequency descending, breaking ties by word ascending -- the mirror image of the eviction comparator -- to produce the final list.

04

Solution & live demo

python
1import heapq
2 
3class Solution:
4 def topKFrequent(self, words: List[str], k: int) -> List[str]:
5 from collections import Counter
6 counts = Counter(words)
7 heap = []
8 for w, c in counts.items():
9 entry = (c, [-ord(ch) for ch in w], w)
10 heapq.heappush(heap, entry)
11 if len(heap) > k:
12 heapq.heappop(heap)
13 heap.sort(key=lambda e: (-e[0], e[2]))
14 return [e[2] for e in heap]
05

Edge cases

k equals number of distinct words

every distinct word is returned, ordered by the same frequency-desc, word-asc rule

all words distinct with count 1

the frequency tie-break becomes the only rule, so the k lexicographically smallest words win

one word repeated many times

it always ranks first regardless of k, since nothing can outrank its frequency

words that are prefixes of each other

standard lexicographic string comparison decides the tie, matching Python's native string ordering

06

Complexity

Time
O(n log k)
Space
O(n)
n distinct words each cost O(log k) heap work; final sort of the k survivors is O(k log k).