javastringalgorithmisomorphic

Check if the two given String are Isomorphic


I am working on the LeetCode problem Isomorphic Strings:

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

Example 2:

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

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.

I have most of the tests working correctly I am just failing some tests.

This is what I have so far:

import java.nio.charset.*;

class Solution {

    public static boolean isIsomorphic(String s, String t) {
        s = s.toLowerCase();
        t = t.toLowerCase();
        int matchCount1 = 0;
        int matchCount2 = 0;
        matchCount1 = checkMatching(s);
        matchCount2 = checkMatching(t);
        System.out.print(matchCount1);
        System.out.print(matchCount2);
        return matchCount1 == matchCount2;
    }

    public static int checkMatching(String s) {
        int count = 0;
        int j = 0;
        for (int i = 0; i < s.length(); i++) { // s.length == 4
            char current = s.charAt(i); // current = 'p'
            j += 1;
            while (j < s.length() - 1) {
                if (current == s.charAt(j)) { // if p != a
                    count += 1;
                    break;
                } else {
                    j++; // j == 2
                }
            }
        }
        return count;
    }

    public static void main(String[] args) {
        String s = "paper";
        String t = "title";

        isIsomorphic(s, t);
    }
}

Failing test:

If the strings s = "foo" and t = "bar", the counts for both return 0, where the answer should be 1 and 0 as "foo" contains two "o" characters.

Any help would be appreciated as I feel like I'm one small change away.


Solution

  • Basically what this task required is to determine whether the two Strings have identical structure, i.e. if string s contains character 'a' at indices 1, 3, 8, we expect string t to have identical character (of whatever kind) at indices 1, 3, 8 and this character shouldn't be encountered anywhere else in the t. It this holds true for every character - the String are isomorphic.

    We can find out it in a linear time O(n) by indexing positions of every character in a Map for both strings. It would be a map of type Map<Character,List<Integer>>, which associates a character with its indices.

    And then we need to find out if all combinations indices of these strings match. For that, we can dump the Values of each Map into a HashSet, it would be a set of type Set<List<Integer>>. And compare these sets using Set.equals() (reminder: two sets are equal if they contain the same elements, regardless of their order).

    That's how implementation might look like:

    public static boolean isIsomorphic(String s, String t) {
        if (s.length() != t.length()) return false; // early kill, if length of these string is not equal they are not isomorphic
        
        String first = s.toLowerCase();
        String second = t.toLowerCase();
        
        Set<List<Integer>> positions1 = getPositions(first);
        Set<List<Integer>> positions2 = getPositions(second);
        
        return positions1.equals(positions2);
    }
    
    public static Set<List<Integer>> getPositions(String str) {
        
        Map<Character, List<Integer>> positionsByCharacter = new HashMap<>();
        
        for (int i = 0; i < str.length(); i++) {
            char next = str.charAt(i);
            
            positionsByCharacter
                .computeIfAbsent(next, k -> new ArrayList<>())
                .add(i);
        }
        return new HashSet<>(positionsByCharacter.values());
    }
    

    main()

    public static void main(String[] args) {
        System.out.println(isIsomorphic("egg", "add"));
        System.out.println(isIsomorphic("foo", "bar"));
        System.out.println(isIsomorphic("paper", "title"));
    }
    

    Output:

    true
    false
    true