LeetCopilot Logo
LeetCopilot
LeetCode Pattern/Hash Map/Hash Map Frequency Counter: The Complete Pattern Guide

Hash Map Frequency Counter: The Complete Pattern Guide

LeetCopilot Team
Dec 22, 2025
12 min read
Hash MapFrequency CounterLeetCode PatternInterview Prep
Master the frequency counter pattern beyond basic counting. Learn when to use Counter vs dict, how to find top-k elements efficiently, and the templates that solve 50+ LeetCode problems.

You see a problem that asks you to "count occurrences" or "find the most frequent element." You know you need to count things... but then what?

Do you use a Counter? A dict? How do you find the top-k most frequent elements efficiently? What if you need to count and then do something with those counts?

This is the gap between knowing how to count and mastering the frequency counter pattern.

The frequency counter is one of the most versatile hash map patterns. It appears in 50+ LeetCode problems, from easy "Valid Anagram" to hard "Top K Frequent Elements." But the pattern isn't just Counter(arr)—it's a systematic approach to counting, querying, and optimizing based on frequencies.

This guide will teach you:

  • When to use frequency counters vs. other patterns
  • The complete template (Python Counter, Java HashMap, JS Map)
  • All major variations (most frequent, k frequent, frequency-based conditions)
  • How to combine frequency counters with other patterns
  • Common mistakes and how to avoid them

Master this, and frequency problems become pattern recognition, not guesswork.

What Is the Frequency Counter Pattern?

The core concept

The frequency counter pattern uses a hash map to count how many times each element appears, then uses those counts to make decisions or find answers.

Structure:

  • Key: The element you're counting
  • Value: How many times it appears (count/frequency)

Example:

python
arr = [1, 2, 2, 3, 3, 3]
freq = {1: 1, 2: 2, 3: 3}

Why it works

Counting with a hash map is O(n) time, O(k) space where k = number of distinct elements.

Without hash map:

python
# Count how many times 3 appears - O(n) per query
count = sum(1 for x in arr if x == 3)

With hash map:

python
# Build once - O(n)
freq = Counter(arr)
# Query - O(1)
count = freq[3]

Real-world analogy

Imagine counting votes in an election:

  • Without frequency map: Count ballots for each candidate separately (slow)
  • With frequency map: Tally as you go, look up any candidate's count instantly (fast)

When to Use Frequency Counters

Quick checklist

Use frequency counter when:

  • ✅ You need to count occurrences of elements
  • ✅ You need to find most/least frequent elements
  • ✅ You need to compare frequencies (anagrams, permutations)
  • ✅ You need to check if frequency meets a condition
  • ✅ You need to group by frequency

Phrases in problem statements

Strong frequency counter signals:

  • "count the number of..."
  • "most frequent / least frequent"
  • "top k frequent"
  • "first unique / non-repeating"
  • "valid anagram" (same frequencies)
  • "permutation" (same frequencies)
  • "majority element" (frequency > n/2)

Frequency counter vs. other patterns

vs. Hash Set:

  • Set: Only need presence (exists or not)
  • Frequency counter: Need count (how many times)

vs. Sorting:

  • Sorting: O(n log n), can find frequencies but slower
  • Frequency counter: O(n), direct access to counts

vs. Array counting:

  • Array: Only works for small, known range (e.g., 0-9, a-z)
  • Frequency counter: Works for any hashable elements

The Universal Template

Python: Three Approaches

Approach 1: Counter (Recommended)

python
from collections import Counter

# Build frequency counter
freq = Counter(arr)

# Access count
count = freq[element]  # Returns 0 if not found

# Most common
most_common = freq.most_common(k)  # Returns [(elem, count), ...]

# Example
arr = ['a', 'b', 'a', 'c', 'a', 'b']
freq = Counter(arr)
print(freq)  # Counter({'a': 3, 'b': 2, 'c': 1})
print(freq.most_common(2))  # [('a', 3), ('b', 2)]

Pros: Clean, built-in, has useful methods
Cons: Slightly more memory overhead

Approach 2: Manual dict

python
# Build frequency counter
freq = {}
for elem in arr:
    freq[elem] = freq.get(elem, 0) + 1

# Or with setdefault
freq = {}
for elem in arr:
    freq.setdefault(elem, 0)
    freq[elem] += 1

Pros: More control, slightly faster
Cons: More verbose

Approach 3: defaultdict

python
from collections import defaultdict

freq = defaultdict(int)
for elem in arr:
    freq[elem] += 1

Pros: Clean, no need for .get()
Cons: Returns 0 for missing keys (can be surprising)

Recommendation: Use Counter for interviews (clearest intent).

Java Template

java
import java.util.*;

// Build frequency counter
Map<Character, Integer> freq = new HashMap<>();
for (char c : s.toCharArray()) {
    freq.put(c, freq.getOrDefault(c, 0) + 1);
}

// Access count
int count = freq.getOrDefault(c, 0);

// Find most frequent (manual)
int maxFreq = 0;
char mostFrequent = ' ';
for (Map.Entry<Character, Integer> entry : freq.entrySet()) {
    if (entry.getValue() > maxFreq) {
        maxFreq = entry.getValue();
        mostFrequent = entry.getKey();
    }
}

JavaScript Template

javascript
// Using Map
const freq = new Map();
for (const elem of arr) {
  freq.set(elem, (freq.get(elem) || 0) + 1);
}

// Access count
const count = freq.get(elem) || 0;

// Find most frequent
let maxFreq = 0;
let mostFrequent = null;
for (const [elem, count] of freq.entries()) {
  if (count > maxFreq) {
    maxFreq = count;
    mostFrequent = elem;
  }
}

// Using object (for simple keys)
const freq = {};
for (const elem of arr) {
  freq[elem] = (freq[elem] || 0) + 1;
}

Pattern 1: Count and Compare

Use case: Compare if two collections have the same frequencies.

Problem: Valid Anagram (LeetCode 242)

Problem: Given two strings s and t, return true if t is an anagram of s.

Insight: Anagrams have identical character frequencies.

Solution 1: Two Counters

python
from collections import Counter

def isAnagram(s: str, t: str) -> bool:
    return Counter(s) == Counter(t)

Complexity: O(n) time, O(k) space where k = alphabet size

Solution 2: Single Counter

python
def isAnagram(s: str, t: str) -> bool:
    if len(s) != len(t):
        return False
    
    freq = Counter(s)
    
    for char in t:
        if char not in freq:
            return False
        freq[char] -= 1
        if freq[char] < 0:
            return False
    
    return True

Optimization: Slightly more memory efficient (one counter instead of two).

Solution 3: Array Counter (if alphabet is small)

python
def isAnagram(s: str, t: str) -> bool:
    if len(s) != len(t):
        return False
    
    # Only for lowercase English letters
    count = [0] * 26
    
    for char in s:
        count[ord(char) - ord('a')] += 1
    
    for char in t:
        count[ord(char) - ord('a')] -= 1
        if count[ord(char) - ord('a')] < 0:
            return False
    
    return all(c == 0 for c in count)

When to use: Only if alphabet is small and known (a-z, 0-9).

Problem: Find All Anagrams (LeetCode 438)

Problem: Find all start indices of anagrams of p in string s.

Pattern: Frequency counter + sliding window

python
from collections import Counter

def findAnagrams(s: str, p: str) -> List[int]:
    if len(p) > len(s):
        return []
    
    result = []
    p_count = Counter(p)
    window_count = Counter(s[:len(p)])
    
    if window_count == p_count:
        result.append(0)
    
    # Slide window
    for i in range(len(p), len(s)):
        # Add new character
        window_count[s[i]] += 1
        
        # Remove old character
        left_char = s[i - len(p)]
        window_count[left_char] -= 1
        if window_count[left_char] == 0:
            del window_count[left_char]
        
        # Check if anagram
        if window_count == p_count:
            result.append(i - len(p) + 1)
    
    return result

Key insight: Combine frequency counter with sliding window for efficiency.

Pattern 2: Find Most/Least Frequent

Use case: Find elements with highest/lowest frequency.

Problem: Top K Frequent Elements (LeetCode 347)

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

Solution 1: Counter + Heap

python
from collections import Counter
import heapq

def topKFrequent(nums: List[int], k: int) -> List[int]:
    # Count frequencies
    freq = Counter(nums)
    
    # Use heap to find top k
    return heapq.nlargest(k, freq.keys(), key=freq.get)

Complexity: O(n + k log n) time, O(n) space

Solution 2: Counter.most_common()

python
from collections import Counter

def topKFrequent(nums: List[int], k: int) -> List[int]:
    freq = Counter(nums)
    return [num for num, count in freq.most_common(k)]

Complexity: O(n + k log n) time (uses heap internally)

Solution 3: Bucket Sort (Optimal)

python
from collections import Counter

def topKFrequent(nums: List[int], k: int) -> List[int]:
    freq = Counter(nums)
    
    # Bucket sort: bucket[i] = elements with frequency i
    buckets = [[] for _ in range(len(nums) + 1)]
    for num, count in freq.items():
        buckets[count].append(num)
    
    # Collect top k from highest frequency buckets
    result = []
    for i in range(len(buckets) - 1, 0, -1):
        result.extend(buckets[i])
        if len(result) >= k:
            return result[:k]
    
    return result

Complexity: O(n) time, O(n) space (optimal!)

When to use each:

  • Heap: General case, works for any k
  • Bucket sort: When you need O(n) time (optimal)

Problem: Sort Characters By Frequency (LeetCode 451)

python
from collections import Counter

def frequencySort(s: str) -> str:
    freq = Counter(s)
    
    # Sort by frequency (descending), then by character (for tie-breaking)
    sorted_chars = sorted(freq.items(), key=lambda x: (-x[1], x[0]))
    
    # Build result
    result = []
    for char, count in sorted_chars:
        result.append(char * count)
    
    return ''.join(result)

Alternative (bucket sort):

python
def frequencySort(s: str) -> str:
    freq = Counter(s)
    buckets = [[] for _ in range(len(s) + 1)]
    
    for char, count in freq.items():
        buckets[count].append(char)
    
    result = []
    for i in range(len(buckets) - 1, 0, -1):
        for char in buckets[i]:
            result.append(char * i)
    
    return ''.join(result)

Pattern 3: Frequency-Based Conditions

Use case: Check if frequencies meet specific conditions.

Problem: First Unique Character (LeetCode 387)

Problem: Find the first non-repeating character in a string.

python
from collections import Counter

def firstUniqChar(s: str) -> int:
    freq = Counter(s)
    
    # Find first character with frequency 1
    for i, char in enumerate(s):
        if freq[char] == 1:
            return i
    
    return -1

Key insight: Build frequency map first, then iterate to find first unique.

Problem: Majority Element (LeetCode 169)

Problem: Find the element that appears more than ⌊n/2⌋ times.

Solution 1: Frequency Counter

python
from collections import Counter

def majorityElement(nums: List[int]) -> int:
    freq = Counter(nums)
    n = len(nums)
    
    for num, count in freq.items():
        if count > n // 2:
            return num

Complexity: O(n) time, O(n) space

Solution 2: Boyer-Moore Voting (Optimal)

python
def majorityElement(nums: List[int]) -> int:
    candidate = None
    count = 0
    
    for num in nums:
        if count == 0:
            candidate = num
        count += 1 if num == candidate else -1
    
    return candidate

Complexity: O(n) time, O(1) space (optimal!)

When to use:

  • Frequency counter: General case, easy to understand
  • Boyer-Moore: When space is critical

Problem: Check If All Characters Have Equal Frequency (LeetCode 1941)

python
from collections import Counter

def areOccurrencesEqual(s: str) -> bool:
    freq = Counter(s)
    counts = list(freq.values())
    return len(set(counts)) == 1

Insight: All frequencies should be the same → set of frequencies has size 1.

Advanced: Frequency Counter + Sliding Window

Combining frequency counter with sliding window is powerful for substring problems.

Problem: Permutation in String (LeetCode 567)

Problem: Check if s2 contains a permutation of s1.

python
from collections import Counter

def checkInclusion(s1: str, s2: str) -> bool:
    if len(s1) > len(s2):
        return False
    
    s1_count = Counter(s1)
    window_count = Counter(s2[:len(s1)])
    
    if window_count == s1_count:
        return True
    
    # Slide window
    for i in range(len(s1), len(s2)):
        # Add new character
        window_count[s2[i]] += 1
        
        # Remove old character
        left_char = s2[i - len(s1)]
        window_count[left_char] -= 1
        if window_count[left_char] == 0:
            del window_count[left_char]
        
        if window_count == s1_count:
            return True
    
    return False

Pattern: Fixed-size sliding window + frequency comparison.

For more on this combination, see Hash Map in Sliding Window.

Common Mistakes

Mistake 1: Not Handling Missing Keys

Wrong:

python
freq = {}
for char in s:
    freq[char] += 1  # KeyError if char not in freq!

Correct:

python
# Option 1: Use .get()
freq = {}
for char in s:
    freq[char] = freq.get(char, 0) + 1

# Option 2: Use Counter
from collections import Counter
freq = Counter(s)

# Option 3: Use defaultdict
from collections import defaultdict
freq = defaultdict(int)
for char in s:
    freq[char] += 1

Mistake 2: Comparing Counters Incorrectly

Wrong:

python
# Comparing lists of values (order matters!)
freq1 = Counter(s1)
freq2 = Counter(s2)
return list(freq1.values()) == list(freq2.values())  # Wrong!

Correct:

python
# Compare Counter objects directly
return Counter(s1) == Counter(s2)

Mistake 3: Not Removing Zero Counts

Wrong:

python
# In sliding window, leaving zero counts
window_count[left_char] -= 1
# Now window_count might have {char: 0}, which != Counter without that char

Correct:

python
window_count[left_char] -= 1
if window_count[left_char] == 0:
    del window_count[left_char]

Mistake 4: Using Array When Hash Map Is Needed

Wrong:

python
# Assuming only lowercase letters, but input has uppercase too
count = [0] * 26  # Only handles a-z!

Correct:

python
# Use Counter for general case
freq = Counter(s)

Rule: Only use array counting when alphabet is small and known.

Complexity Analysis

Time Complexity

Building frequency counter: O(n)

  • Iterate through all n elements once
  • Each insertion/update is O(1) average

Querying frequency: O(1)

  • Hash map lookup

Finding top-k:

  • With heap: O(n + k log n)
  • With bucket sort: O(n)

Space Complexity

Frequency counter: O(k) where k = number of distinct elements

  • Best case: O(1) (all elements same)
  • Worst case: O(n) (all elements distinct)

Practical consideration: For strings with limited alphabet (a-z), space is O(26) = O(1).

Practice Problems

Beginner

  1. Valid Anagram (#242) - Basic frequency comparison
  2. Majority Element (#169) - Frequency condition
  3. First Unique Character (#387) - Find by frequency
  4. Intersection of Two Arrays II (#350) - Frequency matching

Intermediate

  1. Top K Frequent Elements (#347) - Heap or bucket sort
  2. Sort Characters By Frequency (#451) - Sort by frequency
  3. Find All Anagrams (#438) - Frequency + sliding window
  4. Permutation in String (#567) - Frequency + sliding window
  5. Group Anagrams (#49) - Frequency as grouping key

Advanced

  1. Minimum Window Substring (#76) - Frequency + sliding window
  2. Longest Substring with At Most K Distinct (#340) - Frequency + sliding window
  3. Task Scheduler (#621) - Frequency-based greedy

Summary

The frequency counter pattern is a fundamental hash map technique for counting and querying element occurrences.

Key principles:

  • Count first, query later: Build frequency map in O(n), query in O(1)
  • Choose the right tool: Counter for clarity, dict for control, array for small alphabets
  • Combine with other patterns: Sliding window, heap, bucket sort

The template:

python
from collections import Counter

# Build
freq = Counter(arr)

# Query
count = freq[element]

# Top k
top_k = freq.most_common(k)

When to use:

  • ✅ Count occurrences
  • ✅ Find most/least frequent
  • ✅ Compare frequencies
  • ✅ Frequency-based conditions

Common mistakes:

  • ❌ Not handling missing keys
  • ❌ Comparing incorrectly
  • ❌ Not removing zero counts
  • ❌ Using array when hash map is needed

Next steps:

  1. Master the complete hash map guide
  2. Learn Two Sum pattern for complement search
  3. Study grouping pattern for categorization
  4. Practice the beginner problem set

Master frequency counters, and counting problems become pattern recognition.

Want to Practice LeetCode Smarter?

LeetCopilot is a free browser extension that enhances your LeetCode practice with AI-powered hints, personalized study notes, and realistic mock interviews — all designed to accelerate your coding interview preparation.

Also compatible with Edge, Brave, and Opera

Related Tutorials