A solution, optimized for performance.
What does differently to other solutions:
- Only in the absolute worst case it iterates once through text1 and once through text2
- Fails fast: returns false as soon as it encounters a character in text1 that is not part of text2
- Stores histogram as
int[]
, which is much faster than HashMaps or similar
- Can process strings with any character (even emojis )
Example Code:
public static boolean check(String text1, String text2) {
requireNonNull(text1, "text1 must not be null");
requireNonNull(text2, "text2 must not be null");
if (text1 == text2) return true;
var text1Chars = text1.toCharArray();
var text2Chars = text2.toCharArray();
if (text1Chars.length != text2Chars.length) return false;
var text2Counts = new int[Character.MAX_CODE_POINT];
var text2Index = 0;
loopThroughText1:
for (char charOfText1 : text1Chars) {
if (text2Counts[charOfText1] > 0) {
text2Counts[charOfText1]--;
} else {
while (text2Index < text2Chars.length) {
var charOfText2 = text2Chars[text2Index++];
if (charOfText1 == charOfText2) {
continue loopThroughText1;
}
text2Counts[charOfText2]++;
}
return false;
}
}
return text2Index >= text2Chars.length;
}
The corresponding test method:
@ParameterizedTest
@CsvSource({
"a,a,true",
"a,b,false",
"aa,a,false",
"a,aa,false",
"aa,aa,true",
"vhjsd682ahjsvdi7861rUZVFD/Ias6srf871r23,vhjsd682ahjsvdi7861rUZVFD/Ias6srf871r23,true",
"A,a,false",
",,true",
",,false",
})
public void check(String text1, String text2, boolean expected) {
assertEquals(AnagramChecker.check(text1, text2), expected);
}