Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Build the character-frequency map, then build a frequency-of-frequencies map (how many letters share each count). A string is valid if (a) all letters already share one count, or (b) there are exactly two distinct counts and you can delete exactly one character of one letter to merge them. Case (b) holds when the smaller count is 1 occurring once (delete that lone letter), or the larger count is exactly 1 more than the smaller and occurs only once (delete one occurrence of that letter). Otherwise invalid. O(n) time, O(1) space.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you reach for a two-level count (frequency of frequencies) and then enumerate the exact handful of cases a single deletion can repair, rather than trying random deletions.
Where candidates slip
Allowing the 'delete one' to apply per-letter, or forgetting that three distinct frequencies can never be fixed; also mishandling the count-1 case (e.g. "aabbc") versus the count-too-high case (e.g. "aabbccc").
How to stand out
State the invariant first: 'one deletion changes exactly one letter's count by one, so a valid string has at most two distinct frequencies and the gap must be 1-with-single-occurrence — or one of the counts is a lone 1.' Then list the two repair shapes.
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 previewfreq = count lettersHow many distinct counts?13+Explore 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
Brute Force — Try Deleting Each Character
1Hint 1Explore hintHide hint
The definition is operational: 'remove exactly one character and check if the rest are uniform'. What's the most direct simulation?
2Hint 2Explore hintHide hint
First test whether the string is already valid (all frequencies equal). If not, try removing each index in turn and re-test.
3Hint 3Explore hintHide hint
Re-counting frequencies for all n candidate deletions is O(n) each → O(n²). Correct, but you can decide everything from the original counts alone.
A · Core idea
Simulate the definition literally. First check whether s is already valid: build the frequency map and confirm all non-zero counts are equal. If it is, return "YES". Otherwise, for each index i, imagine deleting s[i], rebuild the frequencies, and test uniformity; return "YES" the moment one deletion works.
Why this is the natural first attempt. The problem is phrased as an operation — 'remove exactly one character' — so the mechanical response is to perform every possible removal and check the result. It is unquestionably correct.
Why it's wasteful. Re-counting the entire string after each of the n candidate deletions repeats almost identical work n times. For n = 10⁵ that's ten billion operations. Everything we learn from a deletion is already encoded in the original frequency map — deleting one copy of letter x just decrements freq[x] by one.
The bridge to optimal. Because a deletion only nudges one letter's count down by one, you never need to mutate the string at all. Summarising the frequency map by how many letters share each count tells you in O(1) whether a single decrement can equalise everything.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
s = "aabbc"Array state
base
a:2, b:2, c:1
YESC · Code with teaching comments
Reference implementation previewpublic String isValid(String s) { if (uniform(freqOf(s))) return "YES"; for (int i = 0; i < s.length(); i++) { StringBuilder sb = new StringBuilder(s); sb.deleteCharAt(i);Explore the full codeHide the full code
D · Why it works and complexityO(n²) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
A single deletion is fully described by 'decrement one entry of the frequency map by one'. That means you can reason about all n possible deletions from the frequency map alone, without ever rebuilding the string — which is exactly what the optimal frequency-of-frequencies approach does.
ComplexityO(n²) time, O(1) space — Checking uniformity is O(n) over a 26-letter map. Trying every one of n deletions and re-checking is O(n²). The alphabet-sized maps keep space O(1).
E · Edge cases and pitfalls3Rebuilding the full frequency map for every candidate deletion — O(n²).Explore edge casesHide edge cases
Pitfalls
- Rebuilding the full frequency map for every candidate deletion — O(n²).
- Treating count-0 letters as breaking uniformity — ignore zeros.
- Forgetting the zero-deletion (already valid) check before trying deletions.
Approach 2 of 2 · Optimal
Frequency of Frequencies (Optimal)
1Hint 1Explore hintHide hint
A deletion lowers exactly one letter's count by one. So how many DISTINCT counts can a valid string tolerate?
2Hint 2Explore hintHide hint
Build freq = count of each letter, then counts = count of each frequency value. If there's only one distinct frequency, it's already valid.
3Hint 3Explore hintHide hint
If there are exactly two distinct frequencies f1 < f2, it's valid only when f1 == 1 with a single occurrence (delete that lone letter), or f2 == f1 + 1 with a single occurrence (delete one from that letter). Any other shape, or three+ frequencies, is NO.
A · Core idea
Count letters into freq, then count those frequencies into counts (a map from 'a frequency value' to 'how many letters have it'). The number of distinct keys in counts decides almost everything.
One distinct frequency → valid immediately. Every letter already appears the same number of times; no deletion needed.
Three or more distinct frequencies → impossible. A single deletion changes exactly one letter's count by exactly one. That can collapse at most two frequency groups into agreement; it can never reconcile three different values. Return "NO".
Exactly two distinct frequencies f1 < f2 — only two repair shapes work:
- 1
`f1 == 1` and only one letter has it. That lone letter appears once; delete it entirely (its count goes 1 → 0, dropping out) and every remaining letter shares frequency
f2. Example:"aabbc"→ counts{2:2, 1:1}→ deletec. - 2
`f2 == f1 + 1` and only one letter has `f2`. One letter sticks out by a single extra occurrence; delete one copy of it (its count goes
f2 → f1) and all letters sharef1. Example:"aabbccc"→ counts{2:2, 3:1}→ delete onec.
Any other two-frequency shape — two lone letters ("aabbcd" → {2:2, 1:2}), or a gap larger than one ("aaabbbbcc"-style) — needs more than one deletion, so it's "NO".
Why O(1) space. Both the frequency map and the frequency-of-frequencies map have at most 26 entries regardless of n.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
s = "aabbcd"Array state
freq
a:2, b:2, c:1, d:1
NOC · Code with teaching comments
D · Why it works and complexityO(n) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
The leap is the second level of counting. The first count tells you each letter's frequency; counting those frequencies exposes the structure a single deletion can repair. Because one deletion moves one letter by one step, a valid string is pinned to at most two frequency values with a one-step, single-occurrence gap.
ComplexityO(n) time, O(1) space — One pass to build the frequency map (O(n)), then constant work over at most 26 frequency values. Both maps are bounded by the 26-letter alphabet, so space is O(1).
E · Edge cases and pitfalls8s = "a" — freq {a:1} → counts {1:1} → one distinct frequency → "YES".Explore edge casesHide edge cases
Edge cases handled
s = "a"freq {a:1} → counts {1:1} → one distinct frequency → "YES".s = "aabbccc"counts {2:2, 3:1} → f2-f1==1 and c2==1 → delete one 'c' → "YES".s = "aaabbbcccd"counts {3:3, 1:1} → f1==1 c1==1 → delete lone 'd' → "YES".s = "aaaabbbb"counts {4:2} → one distinct frequency → "YES" with no deletion.
Pitfalls
- Allowing the deletion per-letter — only ONE deletion total is permitted.
- Forgetting that three or more distinct frequencies is always invalid.
- Mixing up the two repair shapes — count-1-once (delete whole) versus gap-of-1-once (delete one copy).
- Not requiring the offending frequency to occur exactly once (c1 == 1 or c2 == 1).
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic String isValid(String s) { int[] freq = new int[26]; for (int i = 0; i < s.length(); i++) freq[s.charAt(i) - 'a']++; Map<Integer, Integer> counts = new HashMap<>(); for (int f : freq) {Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Treating the deletion as per-letter
"aabbcd" has two letters with count 1; fixing both needs two deletions. Only one deletion is allowed, so it must be NO.
Explore the code comparisonHide the code comparison
Treating the deletion as per-letter
"aabbcd" has two letters with count 1; fixing both needs two deletions. Only one deletion is allowed, so it must be NO.
Don't write this
# wrong: assumes any single-count letters can all be dropped
return "YES" if all(c in (1, base) for c in freq.values()) else "NO"Write this instead
if len(counts) == 2:
(f1, c1), (f2, c2) = sorted(counts.items())
if f1 == 1 and c1 == 1: return "YES"
if f2 - f1 == 1 and c2 == 1: return "YES"2Ignoring the three-frequency impossibility
One deletion shifts a single letter's count by one — it can't reconcile three different frequency values, so any counts.size() >= 3 is NO.
Explore the code comparisonHide the code comparison
Ignoring the three-frequency impossibility
One deletion shifts a single letter's count by one — it can't reconcile three different frequency values, so any counts.size() >= 3 is NO.
Don't write this
if (counts.size() >= 2) {
// try to repair regardless of how many distinct counts
}Write this instead
if (counts.size() == 1) return "YES";
if (counts.size() == 2) { /* test the two shapes */ }
return "NO";3Dropping the single-occurrence requirement
f2 - f1 == 1 alone isn't enough; if two letters share the higher count (c2 > 1), deleting one fixes only one of them. The offending frequency must occur exactly once.
Explore the code comparisonHide the code comparison
Dropping the single-occurrence requirement
f2 - f1 == 1 alone isn't enough; if two letters share the higher count (c2 > 1), deleting one fixes only one of them. The offending frequency must occur exactly once.
Don't write this
if f2 - f1 == 1:
return "YES"Write this instead
if f2 - f1 == 1 and c2 == 1:
return "YES"Revise
Carry the pattern into the interview
Pattern to remember
Frequency of frequencies (two-level counting)
Code pattern to memorize
freq = Counter(s)
counts = Counter(freq.values())
if len(counts) == 1: VALID
if len(counts) == 2:
(f1,c1),(f2,c2) = sorted(counts.items()) # f1 < f2
VALID if (f1 == 1 and c1 == 1) or (f2 - f1 == 1 and c2 == 1)
else: INVALIDRules to remember
- 1Count twice: first letters → frequencies, then frequencies → how many letters have them.
- 2One distinct frequency ⇒ already valid, no deletion needed.
- 3Three or more distinct frequencies ⇒ impossible — one deletion changes only one letter's count by one.
- 4With two frequencies, only two repair shapes work: a lone count-1 letter you can delete entirely, or a single letter whose count is exactly one above the rest.
- 5You may delete at most one character total — not one per letter.
Use this pattern when
- Asked if frequencies can be equalised by removing at most one character
- Counts must all match after a single edit, and the edit is a deletion
- Small fixed alphabet, so frequency-of-frequencies is tiny (O(1))
- You see 'all characters appear the same number of times' as the goal
Choose another pattern when
- Allowed to delete more than one character → that's a different (k-deletion) problem
- Edit is a replacement, not a deletion → Anagram-style frequency-difference instead
- Need to find WHICH character to delete → track the offending letter, not just yes/no
- Need the minimum deletions to make valid → count surpluses, don't just test feasibility
Interview takeaway
The trick is the second level of counting: collapse the frequency map into a frequency-of-frequencies. A valid string can have at most two distinct counts, and the gap between them must be repairable by deleting a single character — which is only true in two narrow shapes.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternFrequency of frequencies (two-level counting). When a problem constrains how character counts may differ — especially under a bounded number of edits — count the letters, then count those counts. The compact frequency-of-frequencies map exposes exactly which repairs a single edit can achieve.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Sherlock and the Valid String (alternate framing)Same frequency-of-frequencies logic under a slightly different problem statement.
- Sort Characters By FrequencyComing soonAlso built on a frequency map, then ordering by count.
- Unique Number of OccurrencesComing soonDirectly asks whether all frequency values are distinct — the same second-level count.
- Valid AnagramFrequency comparison between two strings rather than within one.