# Sprint 2 Module Project 3
## Isomorphic Strings
```
"""
Understand
a = "odd"
b = "egg"
output: True ("o" -> "e", "d" -> "g")
a = "oddo"
b = "eggf"
output: False ("o" cannot map to both "e" and "f")
a = "oddh"
b = "egge"
output: False ("o" and "h" cannot both map to "e")
Plan
1. Use a dictionary to keep track of the character mapping from a --> b
2. Whenever you're going to insert a mapping, check if a mapping for
that character already exists.
3. If it already exists and the mapping is not the same, then it can't be isomorphic.
4. If a mapping for that character doesn't yet exist, also check if the character
it's going to be mapped to isn't already mapped by another character (see test case 3)
5. Use a dictionary to track char mapping in a --> b
6. Use a set to track which characters in b have been mapped
Note: I could have used .values() instead of using a set for mappedCharsinB
but that has a slower O(n) runtime for lookup
Runtime: O(length of a or b)
Space: O(length of a or b)
"""
def csIsomorphicStrings(a, b):
if len(a) != len(b):
return False
charMapping = {} # mapping from a->b
mappedCharsInB = set()
for i in range(len(a)):
if a[i] in charMapping: # char in a has already been mapped
# this char in a doesn't map the same char in b
# therefore it can't be isomorphic
if b[i] != charMapping[a[i]]:
return False
else: # char in a hasn't been mapped yet
# check if char in b hasn't been mapped yet
if not b[i] in mappedCharsInB:
charMapping[a[i]] = b[i]
mappedCharsInB.add(b[i])
else:
# if char in b has already been mapped, then some other
# char in a has already been mapped to it
# therefore it can't be isomorphic
return False
return True
```
## Word Pattern
```
"""
Understand
pattern = "abba"
a = "dog cat cat dog"
output: True
pattern = "bb"
a = "dog cat"
output: False
pattern = "ab"
a = "dog dog"
output: False
Plan
This is very similar to the last question, but instead of
comparing character->character
we're now comparing character->word
Runtime: O(max(length of pattern, length of a))
Space: O(max(length of pattern, length of a))
"""
def csWordPattern(pattern, a):
wordList = a.split(' ')
if len(pattern) != len(wordList):
return False
charToWordMapping = {}
mappedWordsInB = set()
for i in range(len(pattern)):
if pattern[i] in charToWordMapping:
if wordList[i] != charToWordMapping[pattern[i]]:
return False
else:
if not wordList[i] in mappedWordsInB:
charToWordMapping[pattern[i]] = wordList[i]
mappedWordsInB.add(wordList[i])
else:
return False
return True
```
## Group Anagrams
```
"""
Understand
strs = ["dog", "god", "cat", "act", "lol"]
output = [["dog", "god"], ["cat", "act"], ["lol"]]
strs = ["dog", "cat", "lol"]
output = [["dog"], ["cat"], ["lol"]]
strs = []
output = []
Plan
1. Sort the characters for each string in the list
2. Realize that anagrams will have the same ordering of characters once sorted (e.g. "god" and "dog" when sorted are both "dgo")
3. Group anagrams together by using a dictionary e.g. {"dgo" -> ["god", "dog"]}
4. Get all the values in the dictionary, put them into one array and sort the array based on their
length
Runtime: O(n * klogk + nlogn) where k = length of word, n = length of strs
Space: O(number of elements in strs)
"""
from collections import defaultdict
def csGroupAnagrams(strs):
anagrams = defaultdict(list)
for word in strs:
anagramOrdering = str(sorted(word))
anagrams[anagramOrdering].append(word)
res = []
for (key, words) in anagrams.items():
res.append(words)
res.sort(reverse=True, key=len)
return res
```