Leetcode 242: Valid Anagram
Вам даються два рядки, s
і t
. Поверніть True
, якщо t
є анаграмою s
, і False
в іншому випадку.
Приклади:
- Вхід:
s = "listen"
,t = "silent"
Вихід:True
- Вхід:
s = "apple"
,t = "applz"
Вихід:False
Що таке анаграма?
Анаграма — це слово або фраза, утворена перестановкою літер іншого слова чи фрази. Наприклад:
- «listen» і «silent» є анаграмами, оскільки можна переставити літери слова «listen», щоб утворити слово «silent».
- Однак «apple» і «applz» не є анаграмами, оскільки їхні літери не збігаються.
Ваше завдання — визначити, чи є два рядки анаграмами один одного.
Проста розв'язка: сортування
Один із простих способів перевірити, чи є два рядки анаграмами, — це сортувати їхні символи. Якщо відсортовані версії обох рядків однакові, вони є анаграмами.
Кроки алгоритму:
- Відсортуйте обидва рядки за алфавітом.
- Порівняйте відсортовані рядки. Якщо вони однакові, поверніть
True
. В іншому випадку повернітьFalse
.
def isAnagram(s: str, t: str) -> bool:
return sorted(s) == sorted(t)
Приклад пояснення:
Припустимо, що s = "listen"
, а t = "silent"
.
- Крок 1: Відсортуйте
s
→sorted(s) = ['e', 'i', 'l', 'n', 's', 't']
. - Крок 2: Відсортуйте
t
→sorted(t) = ['e', 'i', 'l', 'n', 's', 't']
. - Оскільки відсортовані версії однакові, повертається
True
.
Часова складність:
- Сортування кожного рядка займає O(nlogn), де n — довжина рядка.
- Порівняння двох відсортованих рядків займає O(n).
Загальна складність: O(nlogn)
Просторова складність:
- Сортування створює новий список, тому використовує O(n) додаткового простору.
Оптимізована розв'язка: Хеш-таблиця
Підхід сортування працює, але він не найшвидший. Оптимізуємо!
Замість сортування можна використовувати хеш-таблицю (або Counter
в Python), щоб підрахувати частоту кожного символа в обох рядках. Якщо обидва рядки мають однакову частоту символів, вони є анаграмами.
Чому це працює:
Два рядки є анаграмами, якщо для кожного символа:
- Обидва рядки містять однакові символи.
- Кількість появ кожного символа однакова.
Кроки алгоритму:
- Підрахуйте частоту кожного символу в
s
таt
за допомогою хеш-таблиці. - Порівняйте дві хеш-таблиці. Якщо вони однакові, поверніть
True
. В іншому випадку повернітьFalse
.
def isAnagram(self, s: str, t: str) -> bool:
hmap = dict()
for ch in s:
if ch in hmap:
hmap[ch] += 1
else:
hmap[ch] = 1
for ch in t:
if ch in hmap:
hmap[ch] -= 1
if hmap[ch] == 0:
del hmap[ch]
else:
return False
return len(hmap) == 0
Пояснення:
Давайте розглянемо приклад:
Вхід:
s = "listen"
t = "silent"
Крок 1: Створюємо порожню хеш-таблицю (словар).
Ми починаємо з порожньої хеш-таблиці (hmap
), яка буде зберігати кількість символів із рядка s
.
hmap = {}
Крок 2: Підраховуємо символи в s
.
Ми проходимо по символах у s
і оновлюємо хеш-таблицю:
- Для
l
:hmap = {'l': 1}
- Для
i
:hmap = {'l': 1, 'i': 1}
- Для
s
:hmap = {'l': 1, 'i': 1, 's': 1}
- Для
t
:hmap = {'l': 1, 'i': 1, 's': 1, 't': 1}
- Для
e
:hmap = {'l': 1, 'i': 1, 's': 1, 't': 1, 'e': 1}
- Для
n
:hmap = {'l': 1, 'i': 1, 's': 1, 't': 1, 'e': 1, 'n': 1}
Після цього кроку, hmap
містить частоту кожного символу в s
.
Крок 3: Зменшуємо кількість символів для t
.
Тепер ми проходимо по символах у t
.
Для кожного символу:
- Якщо символ є в
hmap
, зменшіть його лічильник. - Якщо лічильник досягне 0, видаліть символ з
hmap
. - Якщо символа немає в
hmap
, повернітьFalse
(рядки не є анаграмами). - Для
s
:hmap = {'l': 1, 'i': 1, 's': 0, 't': 1, 'e': 1, 'n': 1}
→ Видалітьs
, оскільки його лічильник дорівнює 0:hmap = {'l': 1, 'i': 1, 't': 1, 'e': 1, 'n': 1}
- Для
i
:hmap = {'l': 1, 'i': 0, 't': 1, 'e': 1, 'n': 1}
→ Видалітьi
:hmap = {'l': 1, 't': 1, 'e': 1, 'n': 1}
- Для
l
:hmap = {'l': 0, 't': 1, 'e': 1, 'n': 1}
→ Видалітьl
:hmap = {'t': 1, 'e': 1, 'n': 1}
- Для
e
:hmap = {'t': 1, 'e': 0, 'n': 1}
→ Видалітьe
:hmap = {'t': 1, 'n': 1}
- Для
n
:hmap = {'t': 1, 'n': 0}
→ Видалітьn
:hmap = {'t': 1}
- Для
t
:hmap = {'t': 0}
→ Видалітьt
:hmap = {}
Після обробки t
хеш-таблиця порожня.
Крок 4: Перевірка, чи всі лічильники дорівнюють нулю.
Зрештою, ми перевіряємо, чи порожня хеш-таблиця (len(hmap) == 0
). Якщо так, то два рядки є анаграмами. Якщо ні — то вони не є анаграмами.
Для нашого прикладу:
hmap = {}
→ Хеш-таблиця порожня, отже, повертається True
.
Часова складність:
- Підрахунок символів у
s
: O(n), де n — довжина рядкаs
. - Обробка символів у
t
: O(m), де m — довжина рядкаt
. - Загалом: O(n+m).
Оскільки для анаграм n = m
, то часова складність спрощується до: O(n).
Просторова складність:
Хеш-таблиця зберігає кількість символів, що залежить від кількості унікальних символів у s
чи t
. Назвемо це k.
Просторова складність: O(k).
Чому це ефективно?
- Один прохід по кожному рядку: Обидва рядки
s
іt
обробляються лише один раз. - Без сортування: Сортування зайняло б O(nlogn), але тут ми використовуємо лише лінійні операції.
Ця реалізація є ефективною як по часу, так і по пам'яті, що робить її відмінним рішенням для задачі з анаграмами.
Перекладено з: How to Solve the Anagram Problem: A Simple Guide