Top K Frequent Words

Count every word, then keep a min-heap of the k strongest words, where a tie in count goes to the alphabetically earlier word.

Time O(n log k)Space O(n)Code C#
Watch it animatedStep through it, with the running line highlighted. Free with an account.

The idea

First count each word with a dictionary. To keep the k best words, use a min-heap of size k whose top is the weakest word kept: the lowest count, and on equal counts the word that comes later in the alphabet. Each new word is pushed; if the heap then holds k + 1 words, pop the top, the weakest of them. What survives is the top k. Popping gives them weakest first, so reverse the list at the end.

Code

public IList<string> TopKFrequent(string[] words, int k) {
    var count = new Dictionary<string, int>();
    foreach (var w in words) count[w] = count.GetValueOrDefault(w) + 1;
    // weakest on top: the lower count, or on a tie the alphabetically later word
    var heap = new PriorityQueue<string, (int c, string w)>(Comparer<(int c, string w)>.Create(
        (x, y) => x.c != y.c ? x.c.CompareTo(y.c) : string.CompareOrdinal(y.w, x.w)));
    foreach (var (w, c) in count) {
        heap.Enqueue(w, (c, w));
        if (heap.Count > k) heap.Dequeue(); // drop the weakest of k + 1
    }
    var result = new List<string>();
    while (heap.Count > 0) result.Add(heap.Dequeue()); // weakest first
    result.Reverse();
    return result;
}

Tips

In the .NET library

PriorityQueue<TElement, TPriority> (.NET 6+) is a min-heap. A value-tuple priority with a custom Comparer orders by count first and then by word, all in one comparison.