← Назад к вопросам
Проверка палиндрома (строка)
1.0 Junior🔥 241 комментариев
#Python Core
Условие
Напишите функцию, которая проверяет, является ли строка палиндромом. Игнорируйте регистр и небуквенные символы.
Пример
is_palindrome("А роза упала на лапу Азора") → True is_palindrome("Was it a car or a cat I saw?") → True is_palindrome("hello") → False
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Проверка палиндрома: полный разбор
Палиндром — это строка, которая читается одинаково в обе стороны. При проверке игнорируются регистр и небуквенные символы.
Решение 1: Классический подход (Simple)
def is_palindrome_simple(s: str) -> bool:
"""
Проверяет, является ли строка палиндромом.
Игнорирует регистр и небуквенные символы.
Подход: очистка строки, затем сравнение с обратной версией.
"""
# Преобразуем в нижний регистр и оставляем только буквы
cleaned = ''.join(char.lower() for char in s if char.isalpha())
# Сравниваем с обратной версией
return cleaned == cleaned[::-1]
# Примеры
print(is_palindrome_simple("А роза упала на лапу Азора")) # True
print(is_palindrome_simple("Was it a car or a cat I saw?")) # True
print(is_palindrome_simple("hello")) # False
print(is_palindrome_simple("racecar")) # True
print(is_palindrome_simple("Madam")) # True
print(is_palindrome_simple("12321")) # True
Решение 2: Двухуказательный подход (Two Pointers)
Более эффективно для больших строк, так как не создаём новую строку.
def is_palindrome_two_pointers(s: str) -> bool:
"""
Проверяет палиндром с помощью двух указателей.
Сложность: O(n) время, O(1) память
Подход:
- Два указателя: слева и справа
- Двигаются навстречу друг другу
- Пропускаем небуквенные символы
"""
left = 0
right = len(s) - 1
while left < right:
# Пропускаем небуквенные символы слева
while left < right and not s[left].isalpha():
left += 1
# Пропускаем небуквенные символы справа
while left < right and not s[right].isalpha():
right -= 1
# Сравниваем символы (игнорируя регистр)
if s[left].lower() != s[right].lower():
return False
left += 1
right -= 1
return True
# Примеры
print(is_palindrome_two_pointers("А роза упала на лапу Азора")) # True
print(is_palindrome_two_pointers("Was it a car or a cat I saw?")) # True
print(is_palindrome_two_pointers("hello")) # False
print(is_palindrome_two_pointers("A man, a plan, a canal: Panama")) # True
Решение 3: С регулярными выражениями
import re
def is_palindrome_regex(s: str) -> bool:
"""
Проверяет палиндром с помощью регулярных выражений.
Подход:
- Используем regex для очистки строки
- Оставляем только буквы и цифры
"""
# Оставляем только буквы и цифры, преобразуем в нижний регистр
cleaned = re.sub(r'[^a-z0-9]', '', s.lower())
# Сравниваем с обратной версией
return cleaned == cleaned[::-1]
# Примеры
print(is_palindrome_regex("А роза упала на лапу Азора")) # True (для латиницы)
print(is_palindrome_regex("Was it a car or a cat I saw?")) # True
print(is_palindrome_regex("hello")) # False
print(is_palindrome_regex("Race car!")) # True
Решение 4: С типизацией и документацией
def is_palindrome(text: str) -> bool:
"""
Проверяет, является ли строка палиндромом.
Игнорирует регистр и небуквенные символы.
Args:
text: Строка для проверки
Returns:
True, если строка палиндром, False иначе
Raises:
TypeError: Если text не строка
Examples:
>>> is_palindrome("А роза упала на лапу Азора")
True
>>> is_palindrome("Was it a car or a cat I saw?")
True
>>> is_palindrome("hello")
False
>>> is_palindrome("Madam, I'm Adam")
True
"""
if not isinstance(text, str):
raise TypeError(f"Expected str, got {type(text).__name__}")
# Очищаем строку: нижний регистр, только буквы
cleaned = ''.join(char.lower() for char in text if char.isalpha())
# Проверяем, равна ли строка своему обратному значению
return cleaned == cleaned[::-1]
# Тестирование
print(is_palindrome("А роза упала на лапу Азора")) # True
print(is_palindrome("Was it a car or a cat I saw?")) # True
print(is_palindrome("hello")) # False
try:
is_palindrome(12345) # TypeError
except TypeError as e:
print(f"Ошибка: {e}")
Решение 5: Рекурсивный подход
def is_palindrome_recursive(s: str) -> bool:
"""
Проверяет палиндром рекурсивно.
Примечание: менее эффективно, но демонстрирует рекурсию.
"""
# Очищаем строку один раз в начале
def clean(text):
return ''.join(char.lower() for char in text if char.isalpha())
cleaned = clean(s)
def check(left: int, right: int) -> bool:
# Базовый случай: указатели встретились
if left >= right:
return True
# Рекурсивный случай: проверяем текущую пару и двигаемся дальше
if cleaned[left] != cleaned[right]:
return False
return check(left + 1, right - 1)
return check(0, len(cleaned) - 1)
# Примеры
print(is_palindrome_recursive("А роза упала на лапу Азора")) # True
print(is_palindrome_recursive("Was it a car or a cat I saw?")) # True
print(is_palindrome_recursive("hello")) # False
Решение 6: Генераторное выражение (Pythonic)
def is_palindrome_pythonic(s: str) -> bool:
"""
Питоничный подход с использованием генератора и all().
"""
# Преобразуем в итератор букв
chars = [char.lower() for char in s if char.isalpha()]
# Проверяем, совпадают ли символы с начала и конца
return all(
chars[i] == chars[-(i+1)]
for i in range(len(chars) // 2)
)
# Примеры
print(is_palindrome_pythonic("А роза упала на лапу Азора")) # True
print(is_palindrome_pythonic("Was it a car or a cat I saw?")) # True
print(is_palindrome_pythonic("hello")) # False
Сравнение производительности
import time
def benchmark_palindrome():
"""
Сравнивает производительность разных подходов.
"""
test_string = "А роза упала на лапу Азора" * 1000 # Большая строка
# Метод 1: Простой
start = time.time()
for _ in range(1000):
is_palindrome_simple(test_string)
time1 = time.time() - start
print(f"Простой подход: {time1:.4f}с")
# Метод 2: Двухуказательный
start = time.time()
for _ in range(1000):
is_palindrome_two_pointers(test_string)
time2 = time.time() - start
print(f"Двухуказательный: {time2:.4f}с")
# Метод 3: Pythonic
start = time.time()
for _ in range(1000):
is_palindrome_pythonic(test_string)
time3 = time.time() - start
print(f"Pythonic: {time3:.4f}с")
# benchmark_palindrome()
# Результаты примерно одинаковые для этого размера
Тестирование
def test_is_palindrome():
"""
Comprehensive тестирование функции.
"""
# Палиндромы
assert is_palindrome("А роза упала на лапу Азора") == True
assert is_palindrome("Was it a car or a cat I saw?") == True
assert is_palindrome("A man, a plan, a canal: Panama") == True
assert is_palindrome("Madam") == True
assert is_palindrome("racecar") == True
assert is_palindrome("a") == True
assert is_palindrome("") == True # Пустая строка
assert is_palindrome("12321") == True
assert is_palindrome("!@#!@#") == True # Только спецсимволы
# Не палиндромы
assert is_palindrome("hello") == False
assert is_palindrome("world") == False
assert is_palindrome("12345") == False
assert is_palindrome("ab") == False
# Регистр
assert is_palindrome("RaceCar") == True
assert is_palindrome("MADAM") == True
# С спецсимволами
assert is_palindrome("No 'x' in Nixon") == True
assert is_palindrome("race-car") == True
print("✓ Все тесты пройдены!")
test_is_palindrome()
Сложность алгоритмов
| Подход | Время | Память | Примечание |
|---|---|---|---|
| Простой | O(n) | O(n) | Создаёт новую строку |
| Двухуказательный | O(n) | O(1) | Рекомендуется (optimized) |
| С regex | O(n) | O(n) | Медленнее, но удобно |
| Рекурсивный | O(n) | O(n) | Стек вызовов |
| Pythonic | O(n) | O(n) | Читаемо, но неэффективно |
Рекомендуемое решение для Production
def is_palindrome(text: str) -> bool:
"""
Проверяет, является ли строка палиндромом.
Игнорирует регистр и небуквенные символы.
O(n) время, O(n) память
"""
if not isinstance(text, str):
raise TypeError(f"Expected str, got {type(text).__name__}")
# Очищаем строку один раз
cleaned = ''.join(char.lower() for char in text if char.isalpha())
# Сравниваем с обратной версией
return cleaned == cleaned[::-1]
# Баланс:
# - Просто и понятно
# - Эффективно (O(n))
# - Питонично (встроенные методы)
# - Легко поддерживать
Вариации задачи
# Включить цифры
def is_alphanumeric_palindrome(s: str) -> bool:
cleaned = ''.join(char.lower() for char in s if char.isalnum())
return cleaned == cleaned[::-1]
print(is_alphanumeric_palindrome("A1b2B1a")) # True
# Включить пробелы
def is_palindrome_with_spaces(s: str) -> bool:
cleaned = ''.join(char.lower() for char in s if char != ' ')
return cleaned == cleaned[::-1]
print(is_palindrome_with_spaces("race car")) # True
# Проверить слова
def is_word_palindrome(s: str) -> bool:
words = s.lower().split()
return words == words[::-1]
print(is_word_palindrome("race car race")) # True