Open In App

Isomorphic Strings Check

Last Updated : 10 Feb, 2025
Summarize
Comments
Improve
Suggest changes
Like Article
Like
Share
Report
News Follow

Two strings s1 and s2 are called isomorphic if there is a one-to-one mapping possible for every character of s1 to every character of s2. And all occurrences of every character in ‘s1’ map to the same character in ‘s2’.

Examples: 

Input:  s1 = “aab”, s2 = “xxy”
Output: True
Explanation: ‘a’ is mapped to ‘x’ and ‘b’ is mapped to ‘y’.

Input:  s1 = “aab”, s2 = “xyz”
Output: False
Explanation: One occurrence of ‘a’ in s1 has ‘x’ in s2 and other occurrence of ‘a’ has ‘y’.

Naive Solution – O(n^2) Time and O(1) Space

A Simple Solution is to consider every character of ‘s1’ and check if all occurrences of it map to the same character in ‘s2’. 

Using 2 Hash Maps – O(n) Time and O(MAX_CHAR) Space

MAX_CHAR is maximum number of different characters in the two strings. If we talk about lower case alphabet, then its value is 26

The idea is based on the fact that all occurrences of two characters should be at same index. We mainly store the first index of every character and for remaining occurrences, we check if they appear at same first index too.

We mainly use two maps m1 and m2 to store characters as keys and their first indexes as values.

  • If the lengths of s1 and s2 are not same, return false.
  • Do the following for every character in s1 and s2.
    • If this character is seen first time in s1, then store is index in map m1.
    • If this character is seen first time in s2, then store is index in map m2.
    • If indexes in map for both the characters do not match, return false.
C++
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;

bool isIsomorphic(const string &s1, const string &s2) {
  
    if (s1.length() != s2.length()) return false;

    unordered_map<char, int> m1, m2;

    for (int i = 0; i < s1.length(); ++i) {
      
        // If character not seen before, store its 
        // first occurrence index
        if (m1.find(s1[i]) == m1.end()) {
            m1[s1[i]] = i;
        }
        if (m2.find(s2[i]) == m2.end()) {
            m2[s2[i]] = i;
        }

        // Check if the first occurrence indices match
        if (m1[s1[i]] != m2[s2[i]]) {
            return false;
        }
    }
    return true;
}

int main() {
    cout << (isIsomorphic("aab", "xxy") ? "True" : "False");
    return 0;
}
Java Python C# JavaScript

Output
True

Further Optimization using a Fixed Array of size 256

We can avoid the language specific hash function computation and use our own fixed sized array using the fact that the alphabet size 256.

C++
#include <iostream>
#include <vector>
#include <string>
using namespace std;

const int MAX_CHAR = 256;

bool isIsomorphic(const string &s1, const string &s2) {
    if (s1.length() != s2.length()) return false;

    // To store first indices of s1's characters
    vector<int> m1(MAX_CHAR, -1); 
  
     // To store first indices of s2's characters
    vector<int> m2(MAX_CHAR, -1);

    for (int i = 0; i < s1.length(); ++i) {
      
        // If character's first occurrence hasn't been 
        // recorded, store the index
        if (m1[s1[i]] == -1) {
            m1[s1[i]] = i;
        }
        if (m2[s2[i]] == -1) {
            m2[s2[i]] = i;
        }

        // Check if the first occurrence indices match
        if (m1[s1[i]] != m2[s2[i]]) {
            return false;
        }
    }
    return true;
}

int main() {
    cout << (isIsomorphic("aab", "xxy") ? "True" : "False") << endl;
    return 0;
}
Java Python C# JavaScript


Using 1 Hash Map and 1 Hash Set – O(n) Time and O(MAX_CHAR) Space

The idea is to store mapping of characters from s1 to s2 in a map and already seen characters of s2 in a set.

Follow the steps to solve the problem:

  • Create a hashmap of (char, char) to store the mapping of s1 and s2.
  • Now traverse on the string and check whether the current character is present in the Hash map.
    • If it is present then the character that is mapped is there at the ith index or not.
    • Else If s2[i] is present in the set then s2[i] is already mapped to something else, return false
    • Else store mapping of both characters and store s2[i] in the set.

Below is the implementation of the above approach

C++
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <string>
using namespace std;

bool isIsomorphic(const string &s1, const string &s2) {
    if (s1.length() != s2.length()) return false;

    // character mapping from s1 to s2 
    unordered_map<char, char> m1; 
  
    // Already mapped characters in s2
    unordered_set<char> set2; 

    for (int i = 0; i < s1.length(); ++i) {
        char c1 = s1[i], c2 = s2[i];

        // If c1 is already mapped
        if (m1.find(c1) != m1.end()) {
          
            // Check if it maps to the current
            // character in s2
            if (m1[c1] != c2) return false;
        } 
      
        // First occurrence of c1
        else {
          
            // Ensure c2 is not already mapped 
            // to another character
            if (set2.find(c2) != set2.end()) return false;
            
            // Create a new mapping and mark c2 as mapped
            m1[c1] = c2;
            set2.insert(c2);
        }
    }
    return true;
}

int main() {
    cout << (isIsomorphic("aab", "xxy") ? "True" : "False") << endl;
    return 0;
}
Java Python C# JavaScript

Output
True

This method can also be further optimized using fixed sized arrays of size 256 instead of map and set.
 



Next Article
Article Tags :
Practice Tags :

Similar Reads

three90RightbarBannerImg