Как в Python проверить, является ли строка палиндромом?

«Как в Python проверить, является ли строка палиндромом?» — вопрос из категории Алгоритмы, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для проверки строки на палиндром в Python существует два основных подхода: простой с использованием среза и более эффективный с двумя указателями.

1. Простой и "Pythonic" способ (срез)

Этот метод наиболее читаем и краток. Он идеально подходит для большинства случаев.

Логика:

  1. Строка нормализуется: удаляются все небуквенно-цифровые символы и она приводится к нижнему регистру.
  2. Нормализованная строка сравнивается со своей перевернутой копией, полученной с помощью среза [::-1].
def is_palindrome_slice(s: str) -> bool:
    # Оставляем только буквы и цифры, приводим к нижнему регистру
    normalized_s = ''.join(char.lower() for char in s if char.isalnum())
    # Сравниваем строку с её перевернутой версией
    return normalized_s == normalized_s[::-1]

# Пример
print(is_palindrome_slice("A man, a plan, a canal: Panama"))  # True
print(is_palindrome_slice("race a car"))  # False

2. Эффективный способ (два указателя)

Этот подход более производителен для очень длинных строк, так как не создает в памяти новую перевернутую строку (пространственная сложность O(1) против O(N) у среза).

Логика:

  1. Два указателя (left, right) устанавливаются в начало и конец строки.
  2. Указатели движутся навстречу друг другу, сравнивая символы. Если символы не совпадают, строка не является палиндромом.
  3. Пробелы и знаки препинания пропускаются.
def is_palindrome_pointers(s: str) -> bool:
    left, right = 0, len(s) - 1
    while left < right:
        # Пропускаем небуквенно-цифровые символы слева
        while left < right and not s[left].isalnum():
            left += 1
        # Пропускаем небуквенно-цифровые символы справа
        while left < right and not s[right].isalnum():
            right -= 1

        if s[left].lower() != s[right].lower():
            return False

        left += 1
        right -= 1
    return True

# Пример
print(is_palindrome_pointers("A man, a plan, a canal: Panama")) # True