Код
#статьи

Задача: проверить строки на изоморфность

Решаем задачи, которые дают программистам на собеседованиях в IT-компаниях. Сегодня проверяем строки на изоморфность.

Иллюстрация: Polina Vari для Skillbox Media

Сергей Голицын


Senior Java Developer в Covalent Inc. и преподаватель. Больше семи лет в Java-разработке. В свободное время судит хакатоны и делится опытом с начинающими программистами. Пишет статьи для «Хабра» и Medium. Ведёт телеграм-каналы «Полезные ссылки около Java» и Cracking code interview.


Условие. Даны две строки — s и t. Нужно проверить их изоморфность.

Пояснение: строки s и t называются изоморфными, если все вхождения каждого символа строки s можно последовательно заменить другим символом и получить строку t. Порядок символов при этом должен сохраняться, а замена — быть уникальной. Так, два разных символа строки s нельзя заменить одним и тем же символом из строки t, а вот одинаковые символы в строке s должны заменяться одним и тем же символом. Звучит сложно, поэтому просто посмотрите примеры ввода и вывода :)

Ввод и вывод. Пример 1

Ввод: s = "egg", t = "add"
Вывод: true

Ввод и вывод. Пример 2

Ввод: s = "foo", t = "bar"
Вывод: false

Ввод и вывод. Пример 3

Ввод: s = "paper", t = "title"
Вывод: true

Решить эту задачу самостоятельно и на разных языках программирования можно на LeetCode. Наше решение взято из Telegram-канала Сергея Cracking code interview.

Решение

Чтобы решить эту задачу, нам нужно создать два массива. Каждый массив мы будем использовать как словарь со всеми возможными символами, которые находятся в ASCII-таблице. Так мы сократим количество вариантов всего до 256 символов и упростим задачу. А вот если бы мы решали её, используя кодировку Unicode, нам бы понадобился массив побольше.

Массивы нужны, чтобы сопоставлять символы из одной строки с символами из другой. Алгоритм работает так:

  • Сначала мы создаём два массива и заполняем все элементы значением «–1». Это нужно, чтобы в будущем понять, где у нас незанятые элементы.
  • Проходим по символам внутри строк и превращаем каждый символ в ASCII-код — число от 0 до 255. На каждой итерации у нас будет по два таких числа: для строки s и t.
  • Затем проверяем, что коды этих символов не заняты в обоих массивах. Если это так, то записываем в первый массив код символа строки t, а во второй — код символа строки s.
  • Если один из элементов массива уже занят кодом, значит, строки не будут изоморфными.

Вот как этот алгоритм будет реализован на Java:

 public boolean isIsomorphic(String s, String t) {

    int[] sChar = new int[256];
    int[] tChar = new int[256];
    Arrays.fill(sChar, -1);
    Arrays.fill(tChar, -1);

    for(int i = 0; i < s.length(); i++){
      int sCharIdx = s.charAt(i);
      int stCharIdx = t.charAt(i);
      if (sChar[sCharIdx] == -1 && tChar[stCharIdx] == -1){
        sChar[sCharIdx] = stCharIdx;
        tChar[stCharIdx] = sCharIdx;
      } else if (sChar[sCharIdx] != stCharIdx 
                || tChar[stCharIdx] != sCharIdx) {
        return false;
      }
    }
    return true;
  }

Результаты

Временная сложность: O(n) — так как мы перебирали все элементы массива.

Ёмкостная сложность: O(1) — нам нужно определённое количество места в памяти: для двух строк и для двух массивов с символами по 256 байт.

Онлайн-школа для детей Skillbox Kids
Учим детей программированию, созданию игр, сайтов и дизайну. Первое занятие бесплатно! Подробности — по клику.
Узнать больше
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована