I'm currently debating with some friends what is the Big O space complexity of this isAnagram method:
public boolean isAnagram(String firstWord, String secondWord) {
if(firstWord == null || secondWord == null || firstWord.length() != secondWord.length()) {
return false;
}
Map<Character, Integer> charCounts = new HashMap<>();
for(char c1 : firstWord.toCharArray()) {
if(charCounts.containsKey(c1)) {
int currentCount = charCounts.get(c1);
charCounts.put(c1, currentCount + 1);
} else {
charCounts.put(c1, 1);
}
}
for(char c2 : secondWord.toCharArray()) {
if(charCounts.containsKey(c2)) {
int currentCount = charCounts.get(c2);
if(currentCount == 0) {
return false; // not an anagram if it has more of one character than the first word
}
charCounts.put(c2, currentCount - 1);
} else {
return false; // not an anagram if it contains another character
}
}
return true;
}
It's a point of contention because the space used by the method doesn't exactly depend on the input, but a characteristic of the input, namely the number of unique characters in the firstWord.
Let's say m is the length of the first word, and n is the length of the second word. Let's say that k is the number of unique characters in firstWord.
Some of us think that the space complexity is O(k), essentially the number of entries in the map. That is: k is the upper bound on the space used, because k will be the number of entries created in the map, one entry for each unique character.
Some think, it's basically just an O(1) space complexity, because even though the map is dynamically sized in reality, we could also think of it as O(1) and actually just pre-populate the map with counts of 0 for all possible alphabet. The argument against this is that you don't know "all possible alphabet" when latin alphabet is 26 characters, but ascii has 128, and unicode has > 137,000, and other character sets, who knows?
Others argue that we should take into account only m, the length of the first word. In some cases m < k, because it is shorter than k. In the worst case, m > k (because of duplicate characters) and, in very long strings, m will determine the choice of the type of the map's values. e.g. The code given uses "Integer" or 2^32 size counts, but you may need to go to 2^64 or even larger on very long strings. At any rate, this argument contends that m is a factor in how the algorithm scales and so it should be O(m).
A derivative of this last argument is that, on average, for any given character, there are m/k occurrences of that character in the string and the size of a value m/k in computer space is log(m/k), therefore a tighter Big O is O(k * log(m/k)).
Does anyone have any thoughts?