Talentd
FleetCode
Make and follow sheets.Sign in

Isomorphic Strings solution and explanation

EasyHash TableString5 min read48.8% acceptanceUpdated 9 Apr 2026
Isomorphic Strings - Leetcode 205 - PythonNeetCode · 10:07 · 113K viewsWatch on YouTube
9 more videos on this problem
  1. Isomorphic Strings - Leetcode 205 - PythonNeetCode · 10:07 · 113K views
  2. Isomorphic Strings (LeetCode 205) | Full solution using a HashMap | Easy to understandNikhil Lohia · 15:27 · 88K views
  3. Isomorphic Strings | LeetCode problem 205Technosage · 7:09 · 64K views
  4. 205. Isomorphic Strings | Hash Map | StringsAryan Mittal · 15:35 · 8K views
  5. Isomorphic Strings - LeetCode #205 - Python, JavaScript, Java, C++CodingNinja · 17:50 · 5K views
  6. [Coding Interview] [LeetCode Tutorial] LeetCode 205 Isomorphic StringsZiCode · 14:03 · 5K views
  7. Isomorphic Strings #leetcode #topinterview150Deepti Talesra · 6:47 · 2K views
  8. Leetcode | 205. Isomorphic Strings | Easy | Java SolutionDeveloper Docs · 7:49 · 1K views
  9. LeetCode 205 - Isomorphic Strings | Java Solution [EASY]Code with Carter · 11:06 · 1K views
  10. 205. Isomorphic Strings || HashMap || leetCode 205 || Easy || javaLIFE CODING WITH JAVA · 20:43 · 256 views

The problem

Given two strings s and t, determine if they are isomorphic.

Two strings s and t are isomorphic if the characters in s can be replaced to get t.

All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character, but a character may map to itself.

Example 1:

Input: s = "egg", t = "add"

Output: true

Explanation:

The strings s and t can be made identical by:

  • Mapping 'e' to 'a'.
  • Mapping 'g' to 'd'.

Example 2:

Input: s = "foo", t = "bar"

Output: false

Explanation:

The strings s and t can not be made identical as 'o' needs to be mapped to both 'a' and 'r'.

Example 3:

Input: s = "paper", t = "title"

Output: true

Constraints:

  • 1 <= s.length <= 5 * 104
  • t.length == s.length
  • s and t consist of any valid ascii character.

Approach overview

Problem Overview: Given two strings s and t, determine whether they are isomorphic. Two strings are isomorphic if characters in s can be replaced to get t while preserving order. Each character must map to exactly one character, and no two characters can map to the same target character.

Approach 1: One-to-One Character Mapping (O(n) time, O(k) space)

This approach enforces a strict one-to-one mapping between characters in the two strings using hash tables. Iterate through both strings simultaneously and maintain a mapping from s[i] to t[i]. If the character in s was seen before, verify that it maps to the same character in t. To prevent two characters mapping to the same target, maintain a second set or reverse map to track already-mapped characters.

The key insight is that isomorphic strings behave like a bijection: every source character must consistently map to one target character. Hash lookups make each validation constant time, so the entire scan runs in O(n). Space complexity is O(k), where k is the number of unique characters (bounded by the character set). This method relies heavily on a Hash Table for constant-time mapping and works well for general String problems involving character relationships.

Approach 2: Unique Pattern Generation (O(n) time, O(n) space)

Instead of directly mapping characters, convert each string into a structural pattern that represents how characters appear. Traverse the string and assign each new character an increasing index based on its first occurrence. For example, the string egg becomes the pattern [0,1,1], and add produces the same pattern.

Generate this pattern for both strings and compare the resulting sequences. If the patterns match, the strings are isomorphic. This works because the pattern encodes the structure of character repetition and ordering. Pattern generation uses a hash map to track first occurrences and builds an array of indices, giving O(n) time and O(n) space.

This method is conceptually clean and helpful when reasoning about structural equivalence between strings. It also generalizes well to problems where you compare patterns rather than raw characters.

Recommended for interviews: The one-to-one character mapping approach is what interviewers typically expect. It directly models the bijection requirement and demonstrates comfort with hash table lookups and constraint validation during iteration. Mentioning the pattern-generation method shows deeper understanding, but the mapping solution is simpler, uses less memory, and is the most common production implementation.

Approach 1: One-to-One Character Mapping

This approach involves using two hash maps (or dictionaries) to track the character mappings from string s to string t and vice versa. We iterate over the characters of both strings and update the mappings. If at any point the expected character mapping does not match, we conclude that the strings are not isomorphic.

def isIsomorphic(s, t):
    map_s, map_t = {}, {}
    for cs, ct in zip(s, t):
        if map_s.get(cs, ct) != ct or map_t.get(ct, cs) != cs:
            return False
        map_s[cs] = ct
        map_t[ct] = cs
    return True
import java.util.HashMap;

public class IsomorphicStrings {
    public boolean isIsomorphic(String s, String t) {
        HashMap<Character, Character> map_s = new HashMap<>();
        HashMap<Character, Character> map_t = new HashMap<>();
        for (int i = 0; i < s.length(); ++i) {
            char sc = s.charAt(i);
            char tc = t.charAt(i);
            if (map_s.containsKey(sc) && map_s.get(sc) != tc ||
                map_t.containsKey(tc) && map_t.get(tc) != sc)
                return false;
            map_s.put(sc, tc);
            map_t.put(tc, sc);
        }
        return true;
    }
}
#include <unordered_map>
#include <string>
using namespace std;

bool isIsomorphic(string s, string t) {
    unordered_map<char, char> map_s, map_t;
    for (int i = 0; i < s.length(); ++i) {
        if (map_s.count(s[i]) != map_t.count(t[i])) || (map_s[s[i]] != map_t[t[i]]) {
            return false;
        }
        map_s[s[i]] = t[i];
        map_t[t[i]] = s[i];
    }
    return true;
}
function isIsomorphic(s, t) {
    let map_s = {}, map_t = {};
    for (let i = 0; i < s.length; i++) {
        let cs = s[i], ct = t[i];
        if ((cs in map_s && map_s[cs] !== ct) || (ct in map_t && map_t[ct] !== cs)) {
            return false;
        }
        map_s[cs] = ct;
        map_t[ct] = cs;
    }
    return true;
}
#include <stdbool.h>
#include <string.h>

bool isIsomorphic(char * s, char * t) {
    int map_s[256] = {0};
    int map_t[256] = {0};
    int len = strlen(s);
    for (int i = 0; i < len; i++) {
        if (map_s[s[i]] != map_t[t[i]]) {
            return false;
        }
        map_s[s[i]] = map_t[t[i]] = i + 1;
    }
    return true;
}
using System;
using System.Collections.Generic;

public class Solution {
    public bool IsIsomorphic(string s, string t) {
        Dictionary<char, char> map_s = new Dictionary<char, char>();
        Dictionary<char, char> map_t = new Dictionary<char, char>();

        for (int i = 0; i < s.Length; i++) {
            if ((map_s.ContainsKey(s[i]) && map_s[s[i]] != t[i]) ||
                (map_t.ContainsKey(t[i]) && map_t[t[i]] != s[i]))
                return false;

            map_s[s[i]] = t[i];
            map_t[t[i]] = s[i];
        }
        return true;
    }
}

We create two dictionaries to check and store character mappings between strings s and t. During each comparison, consistency is checked, ensuring a valid bidirectional mapping is followed.

Complexity

Time Complexity: O(n), where n is the number of characters in the strings.
Space Complexity: O(1), as the dictionaries at most grow to the size of the character set.

Try this approach in the editor

Approach 2: Unique Pattern Generation

Generate a unique pattern for each string by numbering the characters according to their first appearance. Compare character patterns of the two strings. If the patterns match, the strings are isomorphic.

def generatePattern(s):
    map = {}
    pattern = []
    engine = 1
    for c in s:
        if c not in map:
            map[c] = engine
            engine += 1
        pattern.append(map[c])
    return pattern

def isIsomorphic(s, t):
    return generatePattern(s) == generatePattern(t)
import java.util.*;

public class IsomorphicStrings {
    private List<Integer> generatePattern(String s) {
        Map<Character, Integer> map = new HashMap<>();
        List<Integer> pattern = new ArrayList<>();
        int engine = 1;
        for (char c : s.toCharArray()) {
            if (!map.containsKey(c)) {
                map.put(c, engine++);
            }
            pattern.add(map.get(c));
        }
        return pattern;
    }

    public boolean isIsomorphic(String s, String t) {
        return generatePattern(s).equals(generatePattern(t));
    }
}
#include <vector>
#include <string>
using namespace std;

vector<int> generatePattern(const string &s) {
    vector<int> pattern(s.size());
    unordered_map<char, int> map;
    int engine = 1;
    for (int i = 0; i < s.size(); ++i) {
        if (map.find(s[i]) == map.end()) {
            map[s[i]] = engine++;
        }
        pattern[i] = map[s[i]];
    }
    return pattern;
}

bool isIsomorphic(string s, string t) {
    return generatePattern(s) == generatePattern(t);
}
function generatePattern(s) {
    let map = {}, pattern = [];
    let engine = 1;
    for (let i = 0; i < s.length; ++i) {
        if (!map[s[i]]) {
            map[s[i]] = engine++;
        }
        pattern.push(map[s[i]]);
    }
    return pattern;
}

function isIsomorphic(s, t) {
    return JSON.stringify(generatePattern(s)) === JSON.stringify(generatePattern(t));
}
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

bool generatePattern(char *s, int *pattern) {
    int map[256] = {0};
    int i, engine = 1;
    for (i = 0; s[i]; i++) {
        if (!map[s[i]]) map[s[i]] = engine++;
        pattern[i] = map[s[i]];
    }
    return i;
}

bool isIsomorphic(char *s, char *t) {
    int len = strlen(s);
    int pattern_s[len], pattern_t[len];
    generatePattern(s, pattern_s);
    generatePattern(t, pattern_t);
    for (int i = 0; i < len; i++) {
        if (pattern_s[i] != pattern_t[i])
            return false;
    }
    return true;
}
using System;
using System.Collections.Generic;

public class Solution {
    private List<int> GeneratePattern(string s) {
        Dictionary<char, int> map = new Dictionary<char, int>();
        List<int> pattern = new List<int>();
        int engine = 1;
        foreach (char c in s) {
            if (!map.ContainsKey(c)) {
                map[c] = engine++;
            }
            pattern.Add(map[c]);
        }
        return pattern;
    }

    public bool IsIsomorphic(string s, string t) {
        return GeneratePattern(s).SequenceEqual(GeneratePattern(t));
    }
}

Construct a numerical pattern list for each string, marking character positions and checking for similar distributions across both pattern lists.

Complexity

Time Complexity: O(n), sufficient for pattern derivation.
Space Complexity: O(1), due to bounded map size.

Try this approach in the editor

Approach 3: Hash Table or Array

We can use two hash tables or arrays d_1 and d_2 to record the character mapping relationship between s and t.

Traverse s and t, if the corresponding character mapping relationships in d_1 and d_2 are different, return false, otherwise update the corresponding character mapping relationships in d_1 and d_2. After the traversal is complete, it means that s and t are isomorphic, and return true.

The time complexity is O(n) and the space complexity is O(C). Where n is the length of the string s; and C is the size of the character set, which is C = 256 in this problem.

function isIsomorphic(s: string, t: string): boolean {
    const d1: number[] = new Array(256).fill(0);
    const d2: number[] = new Array(256).fill(0);
    for (let i = 0; i < s.length; ++i) {
        const a = s.charCodeAt(i);
        const b = t.charCodeAt(i);
        if (d1[a] !== d2[b]) {
            return false;
        }
        d1[a] = i + 1;
        d2[b] = i + 1;
    }
    return true;
}
func isIsomorphic(s string, t string) bool {
	d1 := [256]int{}
	d2 := [256]int{}
	for i := range s {
		if d1[s[i]] != d2[t[i]] {
			return false
		}
		d1[s[i]] = i + 1
		d2[t[i]] = i + 1
	}
	return true
}
use std::collections::HashMap;
impl Solution {
    fn help(s: &[u8], t: &[u8]) -> bool {
        let mut map = HashMap::new();
        for i in 0..s.len() {
            if map.contains_key(&s[i]) {
                if map.get(&s[i]).unwrap() != &t[i] {
                    return false;
                }
            } else {
                map.insert(s[i], t[i]);
            }
        }
        true
    }

    pub fn is_isomorphic(s: String, t: String) -> bool {
        let (s, t) = (s.as_bytes(), t.as_bytes());
        Self::help(s, t) && Self::help(t, s)
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
One-to-One Character Mapping

Time Complexity: O(n), where n is the number of characters in the strings.
Space Complexity: O(1), as the dictionaries at most grow to the size of the character set.

Unique Pattern Generation

Time Complexity: O(n), sufficient for pattern derivation.
Space Complexity: O(1), due to bounded map size.

Hash Table or Array–

Complexity analysis

ApproachTimeSpaceWhen to Use
One-to-One Character MappingO(n)O(k)General case; best practical approach using hash maps to enforce bijection
Unique Pattern GenerationO(n)O(n)When comparing structural patterns of strings or explaining the concept visually

Frequently asked questions

Is Isomorphic Strings easy or hard?

Isomorphic Strings is categorized as an Easy problem on LeetCode with an acceptance rate around 48%. The logic is straightforward once you recognize the need for a one-to-one character mapping, making it a common early practice problem for hash tables and string manipulation.

Isomorphic Strings Python/Java solution

In Python, dictionaries are used to store character mappings and sets track used characters. In Java, HashMap and HashSet serve the same role. Both implementations iterate once over the strings, validate mappings, and return false immediately if a conflict appears.

How to solve Isomorphic Strings in O(n)?

Traverse both strings simultaneously and maintain a mapping from characters in the first string to characters in the second. If a character already has a mapping, verify it matches the current character in the other string. Also track used target characters to prevent duplicates. This single pass with hash lookups gives O(n) time.

What is the best approach for Isomorphic Strings?

The best approach uses a one-to-one character mapping with hash maps. Iterate through both strings and map each character from s to t while ensuring no two characters map to the same target. Each lookup and insertion is O(1), so the full algorithm runs in O(n) time with O(k) extra space for unique characters.

Is Isomorphic Strings asked at Google/Amazon/Meta?

Isomorphic Strings is a common entry-level string and hash table problem frequently seen in interviews at companies like Amazon, Google, and Microsoft. It tests understanding of bijective mappings, hash maps, and careful constraint validation during iteration.

What data structure is used in Isomorphic Strings?

The primary data structure is a hash table (or dictionary) to store character mappings. Many solutions also use a set or a second hash map to ensure each target character is mapped only once. These structures provide O(1) lookups and updates.

What is the time complexity of Isomorphic Strings?

The optimal solution runs in O(n) time where n is the length of the strings. Each character pair is processed once and validated using constant-time hash table lookups. Space complexity is typically O(k), where k is the number of unique characters encountered.

Comments

Now write it yourselfClose this page and solve Isomorphic Strings in the editor, without looking.
Practise Isomorphic Strings