Frequency Counting
Build counters for validation, grouping, analytics, ranking signals, anomaly detection, and interview-grade hash-map problems.
What you will be able to do
Frequency counting is the moment hashing becomes more than lookup. Instead of asking whether a key exists, you ask how often it appears. That small change powers validation, grouping, inventory reconciliation, observability metrics, abuse detection, ranking, and many of the most common DSA interview problems.
A Counter Is a Map From Key to Count
A set can tell you that user-42 appeared. A counter can tell you user-42 appeared 19 times. A hash map can store that count using the key as identity and the value as an integer. The repeated operation is simple: read the current count, add one, and write it back.
SkillSkore principle
Use a counter when duplicates carry meaning. If repeated values represent demand, frequency, risk, inventory, votes, or failures, a set throws away information the product may need.
Scenario: Fraud Burst Detection
A fraud system receives login attempts. A single failed attempt is not enough evidence. Repeated failed attempts from the same IP, device, account, or card fingerprint may be a signal. A frequency counter summarizes those repeated observations so the system can trigger investigation or rate limiting.
| Signal | Counter key | Count means | Risk to mention |
|---|---|---|---|
| Failed login burst | ipAddress | Attempts per IP | NAT/shared IPs can cause false positives. |
| Credential stuffing | accountId | Failures per account | Attackers can distribute attempts across accounts. |
| Payment retries | cardFingerprint | Attempts per card | Privacy and retention rules matter. |
| API abuse | apiKey:endpoint | Calls per key and route | High cardinality can increase memory cost. |
| Search demand | normalizedQuery | Repeated searches | Normalization affects grouping accuracy. |
Same Pattern in Java, Python, and JavaScript
The following code counts event names. This exact shape appears in analytics, logs, inventory, anagram checks, voting, ranking preparation, and grouping problems.
import java.util.*;
class EventCounter {
static Map<String, Integer> countEvents(List<String> events) {
Map<String, Integer> counts = new HashMap<>();
for (String event : events) {
counts.put(event, counts.getOrDefault(event, 0) + 1);
}
return counts;
}
}Fixed Array Counter vs Hash Map Counter
Counter shape depends on key space. If the prompt guarantees lowercase English letters, a 26-slot array is compact and fast. If keys are usernames, product IDs, tokens, IPs, or arbitrary Unicode text, a hash map is safer because the key space is dynamic.
| Counter shape | Use when | Trade-off |
|---|---|---|
| Fixed array | Small fixed key space such as a-z | Fast and compact, but only correct under a strict guarantee. |
| Hash map | Dynamic or large key space | Flexible, but uses object overhead and memory per distinct key. |
| Sorted map | Need ordered keys while counting | Maintains order with higher operation cost. |
| Approximate sketch later | Massive streams with memory limits | Saves memory but may accept estimation error. |
Normalize Before Counting
Counters only reflect the keys you feed them. If 'Error', 'error', and ' error ' should be treated as the same event, normalize before counting. If they should remain distinct, preserve them. This is a product rule, not a syntax choice.
Assessment trap
Do not count raw input unless the prompt says raw equality is correct. In production systems, casing, whitespace, tenant scope, locale, and tokenization rules often decide whether the counter is meaningful.
Where Frequency Counting Shows Up
- Anagram and permutation validation.
- Inventory reconciliation and stock movement checks.
- Top searched terms and ranking candidate preparation.
- Rate-limit and fraud feature extraction.
- Log aggregation, observability metrics, and alert thresholds.
- Grouping records by status, category, user, project, or time bucket.
Interview signalFrequently Asked Interview Questions
These are canonical interview patterns for this topic, phrased as concrete problem statements. They avoid vague theory questions and prepare you for the exact reasoning interviewers expect: invariant, edge cases, complexity, and trade-off.
- Given two strings, return whether they are anagrams after lowercasing and keeping only letters a-z.
- Given an integer array, return all values that appear more than floor(n / 3) times.
- Given event names and k, return the k most frequent event names.
Production practiceCompany-Style Practice Examples
These are not claimed as exact company-specific questions. They are the interview patterns repeatedly used by product companies to test whether you can move from brute force to a defensible implementation.
| Example | Brute-force approach | Stronger solution | Production notes |
|---|---|---|---|
| Valid anagram | Sort both strings or repeatedly search. | Normalize and compare frequency counters. | State alphabet/Unicode assumptions and O(n + m) cost. |
| Majority elements | Count every candidate by rescanning. | Use a counter or Boyer-Moore variant depending on memory constraints. | For n/3 there can be at most two answers. |
| Top-k frequent events | Sort all raw events repeatedly. | Count once, then select top k with sorting or heap. | Mention k, cardinality, tie policy, and streaming limits. |
Solved modelInterview Question Solutions
Question 1: Valid Anagram After Normalization
Given two strings, return whether they are anagrams after lowercasing and keeping only letters a-z. Normalize both strings, then count characters from the first and subtract using the second. A count going negative proves mismatch.
class ValidAnagram {
static boolean isAnagram(String left, String right) {
String a = left.toLowerCase().replaceAll("[^a-z]", "");
String b = right.toLowerCase().replaceAll("[^a-z]", "");
if (a.length() != b.length()) return false;
int[] counts = new int[26];
for (char ch : a.toCharArray()) counts[ch - 'a']++;
for (char ch : b.toCharArray()) {
int index = ch - 'a';
counts[index]--;
if (counts[index] < 0) return false;
}
return true;
}
}Question 2: Elements Appearing More Than n / 3 Times
Given an integer array, return all values that appear more than floor(n / 3) times. A direct counter solution is acceptable for this lesson: count every value, then collect values above the threshold. Later you can optimize memory with Boyer-Moore voting.
import java.util.*;
class MajorityNByThree {
static List<Integer> majorityElement(int[] nums) {
Map<Integer, Integer> counts = new HashMap<>();
for (int value : nums) {
counts.put(value, counts.getOrDefault(value, 0) + 1);
}
List<Integer> result = new ArrayList<>();
int threshold = nums.length / 3;
for (Map.Entry<Integer, Integer> entry : counts.entrySet()) {
if (entry.getValue() > threshold) result.add(entry.getKey());
}
return result;
}
}Question 3: Top K Frequent Events
Given event names and k, return the k most frequent event names. Count first, then rank by count. This version sorts distinct keys for clarity. If unique-key cardinality is huge and k is small, a heap is usually better.
import java.util.*;
class TopKEvents {
static List<String> topK(List<String> events, int k) {
Map<String, Integer> counts = new HashMap<>();
for (String event : events) {
counts.put(event, counts.getOrDefault(event, 0) + 1);
}
List<String> names = new ArrayList<>(counts.keySet());
names.sort((a, b) -> {
int byCount = Integer.compare(counts.get(b), counts.get(a));
return byCount != 0 ? byCount : a.compareTo(b);
});
return names.subList(0, Math.min(k, names.size()));
}
}Solved modelWorked Interview Answer
Count normalized event names from a product analytics stream. Normalize keys before counting if the product treats casing or spaces as equivalent. Use a map from normalized event name to count.
import java.util.*;
class NormalizedCounter {
static Map<String, Integer> count(List<String> events) {
Map<String, Integer> counts = new HashMap<>();
for (String event : events) {
String key = event.trim().toLowerCase(Locale.ROOT);
counts.put(key, counts.getOrDefault(key, 0) + 1);
}
return counts;
}
}Hands-on drillTry It Yourself
Practice task
Design a counter for failed-login signals. Define the key, normalization/scope, count lifetime, threshold, and what happens when cardinality grows too high.
Failure patternsCommon Mistakes to Avoid
- Using a set when duplicate count is the signal.
- Counting before normalization or tenant scoping.
- Choosing a fixed array counter without a fixed key-space guarantee.
- Ignoring high-cardinality keys in streams.
- Forgetting integer overflow or counter reset/TTL policy in long-running systems.
Execution guardrailQuick-Start Checklist
- Define the counted unit.
- Define normalization and scope.
- Choose fixed array or hash map.
- State time, memory, and cardinality.
- Explain whether counts are exact, windowed, persisted, or approximate.
Recall drillKnowledge Check
| Question | Strong answer |
|---|---|
| What is a frequency counter? | A structure mapping each key to the number of times it appears. |
| When is a fixed array counter safe? | When the key space is small, fixed, and guaranteed by the problem. |
| Why does cardinality matter? | Memory grows with the number of distinct keys, not just total events. |
VocabularyKey Terms
| Term | Meaning |
|---|---|
| Counter | A map from key to occurrence count. |
| Cardinality | The number of distinct keys seen. |
| Normalization | Transforming input into the key form used for counting. |
| Heavy hitter | A key whose frequency is large relative to the stream. |
| Windowed count | A count retained only for a time range or recent subset. |
Next practiceFurther Reading
- Practice valid anagram, majority element, and top-k frequent elements.
- Review map/set cost models from Lessons 13 and 14.
- Study heaps later because top-k frequency often combines counters with priority queues.