String · 42 of 43
Check if two given strings are isomorphic to each other
Check if one word can turn into another by swapping each letter for a fixed partner letter, where no two letters share a partner.
- Simple way
- time O(n^2)
room O(1) - Clever way
- time O(n)
room O(k)
The problem, simply
You get two strings, s1 and s2. Say if they are isomorphic, which means they have the same shape.
Same shape means you can swap every letter of s1 for a partner letter and get s2. Two rules: a letter always swaps to the same partner, and two different letters can never have the same partner. A letter may be its own partner.
A story to remember it
Picture it
paper and title line up letter by letter. p always becomes t, a becomes i, e becomes l, r becomes e. Same shape.
- looking now
Examples
Same shape
- In
s1 = 'egg', s2 = 'add'- Out
true
e becomes a, g becomes d. Both have the shape one letter, then a doubled letter.
One letter, two partners
- In
s1 = 'foo', s2 = 'bar'- Out
false
The first o wants a, the second o wants r. A letter must keep one partner.
Two letters, one partner
- In
s1 = 'badc', s2 = 'baba'- Out
false
b goes to b, and later d also wants b. Checking only one direction would wrongly say true.
Different lengths
- In
s1 = 'ab', s2 = 'abc'- Out
false
Shapes of different lengths can never match.
Single letters
- In
s1 = 'a', s2 = 'z'- Out
true
One letter, one partner. Always true when both have length 1.
Way 1: the simple way
Two strings have the same shape when every pair of spots agrees. If spots i and j hold the same letter in s1, they must hold the same letter in s2, and if they differ in s1, they must differ in s2.
- If the lengths differ, return false.
- For every pair of spots
i < j, compare "same ins1?" with "same ins2?". - If any pair disagrees, return false.
class Solution {
public boolean isIsomorphic(String s1, String s2) {
if (s1.length() != s2.length()) return false;
int n = s1.length();
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
boolean same1 = s1.charAt(i) == s1.charAt(j);
boolean same2 = s2.charAt(i) == s2.charAt(j);
if (same1 != same2) return false; // shapes differ here
}
}
return true;
}
}How long it takes: every pair of spots, O(n^2). Extra room: O(1).
Way 2: the clever way
Keep the door keeper's two notebooks. In code they are two hash maps, or two arrays of size 256 for plain letters.
- If the lengths differ, return false.
- Walk both strings together. At spot
i, look atx = s1[i]andy = s2[i]. - If the first notebook has
xand says something other thany, return false. - If the second notebook has
yand says something other thanx, return false. - Otherwise write
x to yandy to x, and move on.
Both notebooks agree all the way: paper and title
01 / 07
Two empty notebooks. One says which s2 letter each s1 letter turns into. The other says the same thing backwards.
- checking
- done
- answer
- just added
The second notebook is the one people forget. Here it saves us:
badc and baba: two letters want the same partner
01 / 04
Two empty notebooks. One says which s2 letter each s1 letter turns into. The other says the same thing backwards.
- done
- rejected
- just added
import java.util.*;
class Solution {
public boolean isIsomorphic(String s1, String s2) {
if (s1.length() != s2.length()) return false;
Map<Character, Character> fwd = new HashMap<>(); // s1 letter to s2 letter
Map<Character, Character> back = new HashMap<>(); // s2 letter to s1 letter
for (int i = 0; i < s1.length(); i++) {
char x = s1.charAt(i), y = s2.charAt(i);
if (fwd.containsKey(x) && fwd.get(x) != y) return false;
if (back.containsKey(y) && back.get(y) != x) return false;
fwd.put(x, y);
back.put(y, x);
}
return true;
}
}How long it takes: one walk, O(n). Extra room: one entry per different letter, O(k), where k is the size of the alphabet. For plain text that is at most 256, so many people call it O(1).
Watch out for
- Different lengths: return false before the loop, or
charAtwill crash. - Boxed letters.
fwd.get(x) != yis safe becauseyis a plainchar, so Java compares values. Butfwd.get(x) != back.get(y)compares twoCharacterobjects and can fail for letters outside Java's small cache. Use.equalswhen both sides are boxed. - Isomorphic is about shape, not about letters.
abandbaare isomorphic, and so areabandcd.
What interviewers ask next
- Can you do it with arrays instead of maps? Yes. Keep
last1[c]andlast2[c], the last spot each letter was seen. At each spot the two must be equal, then set both toi. It is the same idea in a tighter form. - Group a list of words by shape? Turn each word into its shape code: replace each letter by the order in which it first showed up.
paperbecomes0 1 0 2 3andtitlealso becomes0 1 0 2 3. Words with the same code go in the same group. - Word pattern: does
abbamatchdog cat cat dog? The same two notebooks, buts2is split into words. - Find all words in a dictionary that match a pattern? Compare each word's shape code with the pattern's shape code.
Remember this
Grown-up words: the notebooks are hash maps, the partner rule is a one-to-one mapping (a bijection), same shape is isomorphism, and the shape code is a canonical form.