LeetCodee

692. Top K Frequent Words

Jump to Solution: Python Java C++ JavaScript C#

Problem Description

Given an array of strings words and an integer k, return the k most frequent strings.

Return the answer sorted by the frequency from highest to lowest. Sort the words with the same frequency by their lexicographical order.

Examples:

Example 1:

Input: words = ["i","love","leetcode","i","love","coding"], k = 2
Output: ["i","love"]
Explanation: "i" and "love" are the two most frequent words.
Note that "i" comes before "love" due to a lower alphabetical order.

Example 2:

Input: words = ["the","day","is","sunny","the","the","the","sunny","is","is"], k = 4
Output: ["the","is","sunny","day"]
Explanation: "the", "is", "sunny" and "day" are the four most frequent words, with the number of occurrence being 4, 3, 2 and 1 respectively.

Constraints:

  • 1 ≤ words.length ≤ 500
  • 1 ≤ words[i].length ≤ 10
  • words[i] consists of lowercase English letters
  • k is in the range [1, The number of unique words]

Python Solution

class Solution:
    def topKFrequent(self, words: List[str], k: int) -> List[str]:
        # Count word frequencies
        word_count = Counter(words)
        
        # Create a heap of (-frequency, word) pairs
        # Using negative frequency to create a max heap
        heap = [(-freq, word) for word, freq in word_count.items()]
        heapify(heap)
        
        # Get top k elements
        result = []
        for _ in range(k):
            freq, word = heappop(heap)
            result.append(word)
            
        return result

Implementation Notes:

  • Uses Counter to count word frequencies
  • Creates a min heap with (-frequency, word) pairs
  • Negative frequency creates max heap behavior
  • Time complexity: O(n log k) where n is the length of words
  • Space complexity: O(n) for the counter and heap

Java Solution

class Solution {
    public List topKFrequent(String[] words, int k) {
        // Count word frequencies
        Map wordCount = new HashMap<>();
        for (String word : words) {
            wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
        }
        
        // Create priority queue with custom comparator
        PriorityQueue> pq = new PriorityQueue<>(
            (a, b) -> a.getValue().equals(b.getValue()) ?
                b.getKey().compareTo(a.getKey()) :
                a.getValue() - b.getValue()
        );
        
        // Add entries to priority queue, maintaining size k
        for (Map.Entry entry : wordCount.entrySet()) {
            pq.offer(entry);
            if (pq.size() > k) {
                pq.poll();
            }
        }
        
        // Build result list
        List result = new ArrayList<>();
        while (!pq.isEmpty()) {
            result.add(0, pq.poll().getKey());
        }
        
        return result;
    }
}

C++ Solution

class Solution {
public:
    vector topKFrequent(vector& words, int k) {
        // Count word frequencies
        unordered_map wordCount;
        for (const string& word : words) {
            wordCount[word]++;
        }
        
        // Custom comparator for priority queue
        auto comp = [](pair& a, pair& b) {
            return a.second > b.second || 
                   (a.second == b.second && a.first < b.first);
        };
        
        // Create min heap
        priority_queue, 
                      vector>, 
                      decltype(comp)> pq(comp);
        
        // Add entries to priority queue
        for (const auto& entry : wordCount) {
            pq.push(entry);
            if (pq.size() > k) {
                pq.pop();
            }
        }
        
        // Build result vector
        vector result(k);
        for (int i = k - 1; i >= 0; i--) {
            result[i] = pq.top().first;
            pq.pop();
        }
        
        return result;
    }
};

JavaScript Solution

/**
 * @param {string[]} words
 * @param {number} k
 * @return {string[]}
 */
var topKFrequent = function(words, k) {
    // Count word frequencies
    const wordCount = new Map();
    for (const word of words) {
        wordCount.set(word, (wordCount.get(word) || 0) + 1);
    }
    
    // Convert to array and sort
    return Array.from(wordCount.entries())
        .sort((a, b) => 
            b[1] === a[1] ? 
            a[0].localeCompare(b[0]) : 
            b[1] - a[1]
        )
        .slice(0, k)
        .map(entry => entry[0]);
};

C# Solution

public class Solution {
    public IList TopKFrequent(string[] words, int k) {
        // Count word frequencies
        Dictionary wordCount = new Dictionary();
        foreach (string word in words) {
            if (!wordCount.ContainsKey(word)) {
                wordCount[word] = 0;
            }
            wordCount[word]++;
        }
        
        // Create priority queue with custom comparison
        var pq = new SortedDictionary<(int freq, string word), string>(
            Comparer<(int freq, string word)>.Create((a, b) => {
                if (a.freq != b.freq) {
                    return a.freq.CompareTo(b.freq);
                }
                return b.word.CompareTo(a.word);
            })
        );
        
        // Add entries to priority queue
        foreach (var entry in wordCount) {
            pq.Add((-entry.Value, entry.Key), entry.Key);
            if (pq.Count > k) {
                pq.Remove(pq.Last().Key);
            }
        }
        
        // Return top k words
        return pq.Values.Take(k).ToList();
    }
}

Implementation Notes:

  • Uses dictionary/map to count word frequencies
  • Different approaches for different languages based on available data structures
  • Python and JavaScript solutions are more concise due to built-in sorting capabilities
  • Java and C++ use priority queues for efficient k-element selection
  • C# uses SortedDictionary as an alternative to priority queue
  • Time complexity: O(n log k) for heap-based solutions, O(n log n) for sorting-based solutions
  • Space complexity: O(n) for storing word frequencies