DSA-003 · FOCUSED PRACTICE
Valid Anagram
Foundation · Java 21 · Version 1 · editorial draft
Java reference and baseline verified on JDK 21: 14645 deterministic checks. Learner drafts are not executed.
Understand the problem
Return whether two strings are anagrams: they must contain exactly the same lowercase letters with the same multiplicities, regardless of order.
- s and t are non-null strings of 0–100,000 characters, each in lowercase a–z. Other alphabets, uppercase, and null are outside the contract.
- Empty strings are anagrams of one another. Different lengths cannot be anagrams. Spaces are not silently ignored; they are excluded by the input alphabet.
- Return boolean. Strings are preserved. Character counts fit int because each length is at most 100,000.
Examples
Input:
s="anagram", t="nagaram"
Output:trueEvery letter has equal multiplicity in both strings.
Input:
s="aab", t="abb"
Output:falseThe sets of letters match, but the counts of a and b do not.
Input:
s="", t=""
Output:trueAll 26 count differences are zero.
Before you start
- Character multiplicity rather than membership
- Explicit lowercase alphabet and count-array indexing
Recognize the structure
Anagrams are an equivalence relation on symbol-count vectors. Set membership loses repeated occurrences. A fixed 26-letter contract permits direct array indexing without hash-table assumptions; unrestricted Unicode would require a different representation and normalization policy.
Your Java attempt
Java 21 · Draft only. Your code is not compiled, executed, or graded here. Run it locally against the examples and edge cases.
Saving stores text in this browser, visible to other people using this browser profile. It does not sync to your account. Loading is always explicit.
No unsaved text changes · 92/20,000 characters
Self-review
Use the checklist to test your explanation. Checks apply to this visit.
Try before revealing
Hint 1
What information remains unchanged when letters are rearranged?
Hint 2
Represent each letter by its count.
Hint 3
Subtract one string’s counts from the other and test the final vector.
Derive the solution
Reveal the baseline, optimized reasoning, and Java code
Sort both character copies
Convert each string to a char array, sort, and compare. For "baba" and "aabb", both canonical arrays become "aabb". Equality of sorted arrays is equivalent to matching multiplicities. The copies cost O(n+m) memory; sorting takes O(n log n+m log m) time for lengths n and m.
Improve the baseline
Discard unnecessary ordering
The question cares how many of each letter exists, not its sorted order. Allocate 26 signed count differences.
Accumulate both sides
For equal-length strings, increment the slot from s and decrement the slot from t at each index. An intermediate difference need not be zero.
Inspect every final slot
A positive slot means surplus in s; a negative slot means surplus in t. Accept only if all differences are zero after every character is processed.
Why it is correct
Initialization
All differences start at zero and describe empty prefixes of both strings.
Preservation
After i positions, each slot equals occurrences in s[0,i) minus occurrences in t[0,i). The paired increment/decrement preserves that exact meaning even when different characters are processed.
Final equivalence
Equal lengths alone are insufficient, but all final count differences zero means each letter occurs equally often. Conversely anagrams give zero in every slot. The finite scan and 26-slot check terminate.
Complete Java reference and baseline
Save as Solution.java. Node definitions and imports are included where needed. The baseline is included for comparison; respect its input-size limits.
import java.util.Arrays;
public final class Solution {
public static boolean isAnagram(String s, String t) {
if (s.length() != t.length()) return false;
int[] difference = new int[26];
for (int i = 0; i < s.length(); i++) {
difference[s.charAt(i) - 'a']++;
difference[t.charAt(i) - 'a']--;
}
for (int count : difference) if (count != 0) return false;
return true;
}
public static boolean baseline(String s, String t) {
char[] a = s.toCharArray(), b = t.toCharArray();
Arrays.sort(a); Arrays.sort(b);
return Arrays.equals(a, b);
}
}
Read the meaningful blocks
Reject unequal lengths first
The paired scan reads corresponding indices safely only after this check.
Index under the declared alphabet
char-a lies in 0..25 only for lowercase a–z; the method is not a Unicode validator.
Check after the whole scan
A nonzero intermediate difference may be canceled later; early rejection there would be incorrect.
Complexity
O(n+m+26) time, including the fixed-alphabet check; unequal lengths can be rejected immediately. O(26)=O(1) auxiliary space under this fixed alphabet.
The sorted-copy baseline uses O(n log n+m log m) time and O(n+m) character-copy storage. Do not compare this deterministic count-array bound to an unstated unbounded alphabet model.
Exact-state walkthroughs
Reveal normal and boundary traces
Imbalances cancel
Input: {"s":"ab","t":"ba"} · Result: true
Step 1 of 5: Compare lengths before scanning paired positions.
Unequal lengths cannot have equal multiplicities.
| Variable | Value |
|---|---|
| sLength | 2 |
| tLength | 2 |
See the affected Java block
1 import java.util.Arrays; 2 public final class Solution { 3 public static boolean isAnagram(String s, String t) { 4 if (s.length() != t.length()) return false; 5 int[] difference = new int[26]; 6 for (int i = 0; i < s.length(); i++) { 7 difference[s.charAt(i) - 'a']++; 8 difference[t.charAt(i) - 'a']--; 9 } 10 for (int count : difference) if (count != 0) return false; 11 return true; 12 } 13 public static boolean baseline(String s, String t) { 14 char[] a = s.toCharArray(), b = t.toCharArray(); 15 Arrays.sort(a); Arrays.sort(b); 16 return Arrays.equals(a, b); 17 } 18 } 19
Highlight locates the relevant statement or block; one trace step may summarize several assignments.
Read the full static trace
- Compare lengths before scanning paired positions.
Unequal lengths cannot have equal multiplicities.
- sLength
2- tLength
2
- Add the s occurrence and subtract the t occurrence.
Each slot is the count in the processed s prefix minus the processed t prefix.
- i
0- sSymbol
"a"- tSymbol
"b"- difference
[1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
- Add the s occurrence and subtract the t occurrence.
Each slot is the count in the processed s prefix minus the processed t prefix.
- i
1- sSymbol
"b"- tSymbol
"a"- difference
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
- Inspect the complete difference vector.
Only the final count differences establish anagram equivalence.
- difference
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
- Return the contract result.
The completed state satisfies the declared output and mutation contract.
- result
true
Same alphabet, different counts
Input: {"s":"aab","t":"abb"} · Result: false
Step 1 of 6: Compare lengths before scanning paired positions.
Unequal lengths cannot have equal multiplicities.
| Variable | Value |
|---|---|
| sLength | 3 |
| tLength | 3 |
See the affected Java block
1 import java.util.Arrays; 2 public final class Solution { 3 public static boolean isAnagram(String s, String t) { 4 if (s.length() != t.length()) return false; 5 int[] difference = new int[26]; 6 for (int i = 0; i < s.length(); i++) { 7 difference[s.charAt(i) - 'a']++; 8 difference[t.charAt(i) - 'a']--; 9 } 10 for (int count : difference) if (count != 0) return false; 11 return true; 12 } 13 public static boolean baseline(String s, String t) { 14 char[] a = s.toCharArray(), b = t.toCharArray(); 15 Arrays.sort(a); Arrays.sort(b); 16 return Arrays.equals(a, b); 17 } 18 } 19
Highlight locates the relevant statement or block; one trace step may summarize several assignments.
Read the full static trace
- Compare lengths before scanning paired positions.
Unequal lengths cannot have equal multiplicities.
- sLength
3- tLength
3
- Add the s occurrence and subtract the t occurrence.
Each slot is the count in the processed s prefix minus the processed t prefix.
- i
0- sSymbol
"a"- tSymbol
"a"- difference
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
- Add the s occurrence and subtract the t occurrence.
Each slot is the count in the processed s prefix minus the processed t prefix.
- i
1- sSymbol
"a"- tSymbol
"b"- difference
[1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
- Add the s occurrence and subtract the t occurrence.
Each slot is the count in the processed s prefix minus the processed t prefix.
- i
2- sSymbol
"b"- tSymbol
"b"- difference
[1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
- Inspect the complete difference vector.
Only the final count differences establish anagram equivalence.
- difference
[1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
- Return the contract result.
The completed state satisfies the declared output and mutation contract.
- result
false
Test the contract
Input:
s="a", t=""
Output:falseLength mismatch.
Input:
s="aa", t="aa"
Output:trueRepeated multiplicity.
Input:
s="ab", t="ba"
Output:trueOrder does not matter.
Input:
s="abc", t="abd"
Output:falseOne differing symbol.
Common mistakes and counterexamples
Compare letter sets only
Counterexample: "aab" and "abb" are not anagrams.
Keep multiplicities.
Reject on an intermediate nonzero count
Counterexample: "ab" and "ba" have a temporary imbalance but are anagrams.
Inspect final differences after all characters.
Use a fixed array without an alphabet contract
Counterexample: Uppercase A does not map into char-a slots.
Keep the input contract or change the representation.
Follow-ups
Accept arbitrary Unicode code points.
Count int code points and specify case folding/normalization explicitly. Java char units do not automatically correspond to complete characters.
Group a list of anagrams.
Use the entire count vector as a stable key. A sum of character codes is insufficient because different multisets can share that sum.
Find every anagram window inside a longer string.
Maintain a fixed-length sliding count difference, updating only entering and leaving symbols. Define empty-pattern behavior and compare windows rather than the entire strings.