Hook: This is one of those interview questions that looks tiny, but it tests whether you can turn messy text into a clean data structure — like sorting a pile of receipts into labeled folders.
Question: How do you count occurrences of each word in a sentence or paragraph using Java?
Answer: I would scan the text word by word, normalize each word to a common form such as lowercase, and store counts in a Map. Each time I see a word, I either add it to the map with count 1 or increase its existing count. This gives fast counting and handles repeated words naturally.
Interview-Ready Answer: I’d use a
Map<String, Integer> to count words. First I normalize the text, usually by converting to lowercase and extracting words cleanly so punctuation does not create fake tokens. Then I walk through each word and update its count with merge or getOrDefault. That gives me an average O(n) solution, where n is the number of words, and it scales well for large text.
Detailed Explanation: The goal is to transform raw text into counts. In simple words, you want a frequency table: a list of words and how many times each one appears. A Map is perfect because it connects each word to one number.
Java and java count as the same word. This step avoids split counts caused by case differences.[\p{L}\p{Nd}']+ finds letters, digits, and apostrophes, so don't stays one word instead of becoming don and t.merge(word, 1, Integer::sum) is a neat way to say “add one, or start at one if missing.”LinkedHashMap; if you want sorted keys, use TreeMap.A HashMap stores keys in buckets based on their hash code. A hash code is a number used to place items quickly, so lookups are usually fast. When you count words, each unique word becomes one key, and the map updates that key many times. That is why the average cost per update is close to constant time.
| Approach | When to use | Trade-off |
|---|---|---|
HashMap | Fast counting | No ordering |
LinkedHashMap | Keep first-seen order | Slight extra memory |
TreeMap | Alphabetical order | O(log k) updates |
Here, k is the number of distinct words. For most interview solutions, HashMap or LinkedHashMap is the best default because counting stays simple and fast.
O(n), where n is the number of words scanned.O(k) for distinct words, because each unique word needs one map entry.hello,world or end..word and word, should count together. In interviews, say your rule clearly.Locale.ROOT for stable lowercase conversion; this avoids language-specific surprises.Memory Hook: Think of words as mail and the map as a row of labeled mailboxes: every time the same letter arrives, you drop one more copy into the same box.
Real-World Story: Imagine a chat app that scans messages to show trending words in a support channel. The service reads each message, normalizes it, and updates counts for dashboards and search suggestions. If the developer forgets to remove punctuation, the dashboard may show error, error!, and error? as three separate “top words,” which makes the trend data wrong.
In production, that bug looks harmless at first, but users notice weird analytics: support teams search for a term and miss messages because the index is fragmented. Logs often show lots of near-duplicate tokens, and the UI may display misleading top keywords. The fix is not in the database — it is in text normalization before counting.
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
// Matches words made of letters, digits, and apostrophes.
// Using a regex extractor is safer than splitting only on spaces,
// because punctuation and repeated whitespace are common in real text.
private static final Pattern WORD_PATTERN = Pattern.compile("[\\p{L}\\p{Nd}']+");
public static Map<String, Integer> countWords(String text) {
Map<String, Integer> counts = new LinkedHashMap<>();
// Null or blank input should not blow up; an empty result is more useful.
if (text == null || text.trim().isEmpty()) {
return counts;
}
// Locale.ROOT keeps lowercasing predictable across machines.
String normalized = text.toLowerCase(Locale.ROOT);
Matcher matcher = WORD_PATTERN.matcher(normalized);
while (matcher.find()) {
String word = matcher.group();
// merge means: if absent, start at 1; if present, add 1.
counts.merge(word, 1, Integer::sum);
}
return counts;
}
public static void main(String[] args) {
String sample = "Java is great. Java, Java! Don't stop learning Java.";
System.out.println("Sample input: " + sample);
System.out.println("Word counts : " + countWords(sample));
// Edge case: punctuation and blanks should produce an empty map.
String edgeCase = " ... ";
System.out.println("Edge input : [" + edgeCase + "]");
System.out.println("Word counts : " + countWords(edgeCase));
// Failure path example: null is handled safely.
System.out.println("Null input : " + countWords(null));
}
}Follow-up & Tricky Questions:
TreeMap instead of a HashMap. It keeps keys sorted, but each update becomes O(log k) instead of average O(1).LinkedHashMap. It stores entries in insertion order, which is useful when you want the output to match the original text flow.BufferedReader instead of loading the whole file into memory. That keeps memory use lower and is the standard approach for large input.Set of stop words and skip them during counting. This is common in search and analytics systems.ConcurrentHashMap with atomic updates. Otherwise, counts can be lost during race conditions, which are timing bugs caused by threads interfering with each other.Locale.ROOT. That avoids splitting non-English letters incorrectly.split(" ") handle all whitespace? No. It fails on multiple spaces and tabs unless you use a whitespace regex, and even then punctuation still needs cleanup.hello the same as Hello? Only if you normalize case first. If you forget, you will count them as two different words.don't counted as one word, your tokenizer must allow apostrophes inside tokens.Common Mistakes:
split(" ").Locale.ROOT before counting.HashMap for speed, LinkedHashMap for stable order, or TreeMap for sorting.Memory Hook: “Same word, same mailbox.” Picture each word walking to its own labeled mailbox, and every repeat just drops in one more letter.
Cheat Sheet:
Map<String, Integer> for word frequencies.HashMap is average O(1) per update.LinkedHashMap keeps insertion order.Practice Tasks:
can't is counted as one word, but rock-n-roll is split into three.