Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
If the length is odd, the answer is −1 (you can't split into two equal halves). Otherwise split the string into halves a and b, count the character frequencies of each, and the minimum number of changes equals the sum of the positive surpluses of a over b — i.e. for every letter, how many more times it appears in a than in b. That equals (sum of absolute frequency differences) / 2. O(n) time, O(1) space (26 counters).
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you reduce 'make these anagrams' to a pure frequency-count problem, and whether you correctly count edits as surplus-in-one-half rather than double-counting both halves.
Where candidates slip
Summing the absolute differences without dividing by two (that's the Making Anagrams answer, where both strings can be edited), or forgetting the odd-length → −1 guard.
How to stand out
State that one replacement fixes one surplus-and-deficit pair simultaneously, so the answer is the surplus count, equivalently sum(|diff|)/2. Mention the fixed 26-array gives O(1) space.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewString sLength even?NoYesExplore the full treeCollapse the tree
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Sort Each Half and Compare Letter Counts (Baseline)
1Hint 1Explore hintHide hint
Two strings are anagrams iff their sorted forms are identical. How could sorting help you measure the gap?
2Hint 2Explore hintHide hint
Sort both halves. Walk them together; every position where they disagree hints at a needed change — but sorting muddies the exact count.
3Hint 3Explore hintHide hint
Counting is cleaner: tally each half's letters and compare tallies directly instead of sorting.
A · Core idea
The definition of anagram is 'same characters with the same multiplicities'. A natural first instinct is to sort each half so equal multisets line up, then measure how far apart they are.
Why sorting feels right but is the long way around. Sorting groups identical letters together, so two anagrams become byte-identical after sorting. To count edits, though, you don't actually care about order at all — you care about how many of each letter each half holds. Sorting throws away nothing useful but adds a log-factor and forces you to re-derive counts by scanning runs.
Why we move on. The whole computation is a histogram comparison. A histogram is built in one O(n) pass with a 26-slot array; sorting is strictly more work for the same information. Open with this to prove you know the anagram definition, then replace it with frequency counting.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
s = "aaabbb"Array state
half a
count a = {a:3}
3C · Code with teaching comments
Reference implementation previewpublic int anagram(String s) { int n = s.length(); if (n % 2 != 0) return -1; char[] a = s.substring(0, n / 2).toCharArray(); char[] b = s.substring(n / 2).toCharArray();Explore the full codeHide the full code
D · Why it works and complexityO(n log n) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Sorting and frequency-counting both reduce a string to its multiset of characters. Counting reaches that multiset in O(n) with O(1) space, so prefer it the moment you only need per-letter totals.
ComplexityO(n log n) time, O(n) space — Sorting each half of size n/2 costs O(n log n). The comparison is O(n). Sorted copies use O(n) space.
E · Edge cases and pitfalls5s = "" — Even length 0 → both halves empty → 0 changes.Explore edge casesHide edge cases
Edge cases handled
s = ""Even length 0 → both halves empty → 0 changes.s = "ab"a = "a", b = "b". Surplus a:1 → 1 change.
Pitfalls
- Sorting then comparing positions instead of counts — fragile for measuring edits.
- Forgetting the odd-length −1 guard before slicing.
- Paying O(n log n) when an O(n) histogram gives the same answer.
Approach 2 of 2 · Optimal
Single Frequency-Difference Pass (Optimal)
1Hint 1Explore hintHide hint
You don't need order — you need per-letter counts. What single array tracks the balance between the two halves?
2Hint 2Explore hintHide hint
Use one int[26]: increment for each char in the first half, decrement for each char in the second half.
3Hint 3Explore hintHide hint
After the pass, every positive entry is a letter the first half has in surplus. Sum those positives — that's the minimum number of replacements.
A · Core idea
Maintain a single int[26] balance array. Walk the first half adding +1 to each letter's slot, then walk the second half subtracting 1. After both passes, slot c holds freq_a(c) − freq_b(c). The minimum number of changes is the sum of the positive slots.
Why positive slots are exactly the edit count. A positive value at letter c means the first half has that many more cs than the second half. To make the second half an anagram, each of those missing cs must be created by replacing some other character in the second half. Crucially, the surplus letters in a and the deficit letters in b come in matched pairs: every +1 somewhere is balanced by a −1 elsewhere, because both halves have the same length. So one replacement simultaneously removes a surplus and fills a deficit. Counting just the positives (or equivalently sum(|balance|)/2) avoids double-counting that single fix.
Why O(1) space. The alphabet is fixed at 26 letters, so the balance array never grows with n. That is the line to say aloud: 'O(n) time, O(1) space because the alphabet is constant.'
Why the odd guard comes first. If n is odd the halves differ in size and no number of replacements can equalise the multisets — return −1 before touching the array.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
s = "xaxbbbxx"Array state
after add a
a="xaxb" → x:+2, a:+1, b:+1
1C · Code with teaching comments
D · Why it works and complexityO(n) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
Encoding 'first half minus second half' into one signed histogram turns a two-string comparison into a single sweep. The sum of positive surpluses equals sum(|diff|)/2; the /2 is the giveaway that one replacement heals both a surplus and a deficit at once — exactly what separates this from Making Anagrams.
ComplexityO(n) time, O(1) space — One pass over n characters with O(1) work each = O(n). A fixed 26-element array is O(1) extra space regardless of n.
E · Edge cases and pitfalls6s = "xyyx" — a="xy", b="yx" — identical multisets → balance all zero → 0 changes.Explore edge casesHide edge cases
Edge cases handled
s = "xyyx"a="xy", b="yx" — identical multisets → balance all zero → 0 changes.s = "mnop"a="mn", b="op" — surplus m:+1, n:+1 → 2 changes.s = "a"Odd length → −1.
Pitfalls
- Summing |diff| without /2 — that overcounts because a surplus and its matching deficit are one fix.
- Allocating a HashMap when a 26-int array is O(1) and faster.
- Counting only one half and forgetting to subtract the other.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic int anagram(String s) { int n = s.length(); if (n % 2 != 0) return -1; int[] balance = new int[26]; int half = n / 2;Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Double-counting the difference
Each replacement fixes a surplus in one half AND the matching deficit in the other at the same time. Summing all |diffs| counts both ends of that single fix.
Explore the code comparisonHide the code comparison
Double-counting the difference
Each replacement fixes a surplus in one half AND the matching deficit in the other at the same time. Summing all |diffs| counts both ends of that single fix.
Don't write this
return sum(abs(count_a[c] - count_b[c]) for c in set(a) | set(b))Write this instead
return sum(max(0, count_a[c] - count_b[c]) for c in count_a)2Missing the odd-length guard
Slicing an odd string gives halves of size floor(n/2) and ceil(n/2); comparing them yields a wrong positive number instead of the required −1.
Explore the code comparisonHide the code comparison
Missing the odd-length guard
Slicing an odd string gives halves of size floor(n/2) and ceil(n/2); comparing them yields a wrong positive number instead of the required −1.
Don't write this
char[] a = s.substring(0, n / 2).toCharArray();
char[] b = s.substring(n / 2).toCharArray();Write this instead
if (n % 2 != 0) return -1;
char[] a = s.substring(0, n / 2).toCharArray();
char[] b = s.substring(n / 2).toCharArray();3Indexing the wrong second half
Off-by-one on the split sends the middle character to the wrong half, corrupting both counts.
Explore the code comparisonHide the code comparison
Indexing the wrong second half
Off-by-one on the split sends the middle character to the wrong half, corrupting both counts.
Don't write this
char[] b = s.substring(n / 2 + 1).toCharArray();Write this instead
char[] b = s.substring(n / 2).toCharArray();Revise
Carry the pattern into the interview
Pattern to remember
Frequency-difference of two halves
Code pattern to memorize
n = len(s)
if n is odd: return -1
a, b = s[:n/2], s[n/2:]
count = freq(a) - freq(b) # per character
return sum(c for c in count if c > 0) # == sum(|c|)/2Rules to remember
- 1Odd length → immediately −1; halves of unequal size can never be anagrams.
- 2You only need to change characters in one half — count surplus letters in
a, not both directions. - 3Sum of positive differences equals
sum(|diff|)/2— each surplus inapairs with a deficit inb. - 426 fixed counters means O(1) space, not O(n) — say this out loud.
- 5Changing a character is one operation; you never delete or insert, only replace.
Use this pattern when
- Two equal-length strings (or two halves) and you need edits to make them anagrams
- The cost is defined per-character-replacement, not per-deletion
- Order doesn't matter — only multiset of characters
- Lowercase-only alphabet so a fixed 26-slot array works
Choose another pattern when
- Deletions allowed from both strings → Making Anagrams (sum of all |diffs|, not /2)
- You must check equality, not count edits → just compare sorted strings or frequency maps
- Unicode / huge alphabet → use a hash map, not a 26-array
- Substrings / sliding window of anagrams → that's a different (window) pattern
Interview takeaway
Replacing characters in one half to match the other costs exactly the number of surplus letters in that half. Because every surplus in `a` is mirrored by a deficit in `b`, summing positive differences (or `sum(|diff|)/2`) gives the answer in one frequency pass.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternFrequency-difference counting. Whenever a problem is about rearranging or replacing characters to reach an anagram, reduce each side to a 26-slot histogram and read the answer off the differences. Counting how many edits = sum of positive surpluses; counting deletions across both strings = sum of all absolute differences.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Making AnagramsTwo separate strings, deletions allowed from both — answer is sum of ALL |diffs|, no /2.
- Valid AnagramJust decide YES/NO — one frequency map, check it returns to all zeros.
- Group AnagramsBucket by the sorted (or count-tuple) signature of each word.
- Find All Anagrams in a StringComing soonSliding window of fixed size with a running frequency match.