Python: определение палиндрома в строке - методы и примеры

Раздел: Обучение Python -> Учебные задания

Проверка строки на палиндром: основные подходы

В учебных заданиях по Python часто встречается задача определения, является ли строка палиндромом. Строка считается палиндромом, если она читается одинаково с обеих сторон. Далее рассмотрены различные способы решения с примерами кода и анализом возможных проблем.

Вопрос: Как проще всего проверить, является ли строка палиндромом, игнорируя регистр и пробелы?

Самое компактное решение использует срез [::-1] для получения обратной строки. Перед сравнением строка приводится к нижнему регистру и из нее удаляются пробелы.


def is_palindrome(s):
    s = s.lower().replace(' ', '')
    return s == s[::-1]

программы python задачи (задачи по python)

Пояснение: Функция lower() преобразует все символы строки в нижний регистр. replace(' ', '') удаляет все пробелы. Затем исходная строка сравнивается с перевернутой копией. Если они совпадают, возвращается True, иначе False.

Типичная ошибка: Сравнение строки без предварительной обработки. Если строка содержит пробелы или буквы разного регистра, результат может быть неверным. Например, строка «А роза упала на лапу Азора» содержит пробелы и заглавные буквы. Без обработки она не будет распознана как палиндром.

Решение: Всегда перед сравнением приводить строку к единому регистру и удалять незначащие символы (пробелы, знаки препинания).

Вопрос: Как выполнить проверку палиндрома без создания новой строки в памяти (in-place)?

Алгоритм с двумя указателями позволяет сравнивать символы напрямую, не создавая перевернутую копию. Это экономит память, особенно для больших строк.


def is_palindrome_two_pointer(s):
    s = s.lower().replace(' ', '')
    left, right = 0, len(s) - 1
    while left < right:
        if s[left] != s[right]:
            return False
        left += 1
        right -= 1
    return True

информатика программа python (программа по информатике на python)

Пояснение: После очистки строки указатели двигаются навстречу. Если на какой-то паре символы различаются, функция возвращает False. Если все пары совпали, возвращается True. Временная сложность O(n), пространственная O(1) (если не считать преобразование строки).

Проблема: Простая замена пробелов не учитывает другие знаки препинания. Например, строка «Madam, I'm Adam» содержит запятую и апостроф. Они будут мешать сравнению.

Решение: Использовать проверку isalnum() или регулярное выражение для удаления всех неалфавитно-цифровых символов. Пример: ''.join(filter(str.isalnum, s)).lower().

Вопрос: Можно ли решить задачу с помощью рекурсии?

Рекурсивный подход сравнивает первый и последний символ, после чего рекурсивно обрабатывает подстроку без этих символов. Этот способ нагляден, но ограничен глубиной рекурсии Python.


def is_palindrome_recursive(s):
    s = s.lower().replace(' ', '')
    if len(s) <= 1:
        return True
    if s[0] != s[-1]:
        return False
    return is_palindrome_recursive(s[1:-1])

Пояснение: Базовый случай: строка длины 0 или 1 является палиндромом. Иначе проверяется совпадение крайних символов и вызывается функция для подстроки без первого и последнего символа. Рекурсия продолжается до тех пор, пока не будет найдено несовпадение или строка не сократится до базового случая.

Ошибка: Для длинных строк Python может выбросить исключение RecursionError из-за превышения максимальной глубины рекурсии (обычно 1000). Для строк длиннее 500 символов рекурсия не рекомендуется.

Альтернатива: Увеличить лимит рекурсии с помощью sys.setrecursionlimit(10000), но это может привести к переполнению стека. Лучше использовать итеративные методы.

Вопрос: Как проверить палиндром с помощью встроенной функции reversed?

Функция reversed() возвращает итератор, который можно сравнить с исходной строкой через всесимвольное сравнение.


def is_palindrome_reversed(s):
    s = s.lower().replace(' ', '')
    return all(a == b for a, b in zip(s, reversed(s)))

Пояснение: zip(s, reversed(s)) попарно соединяет символы исходной строки и обратной. Функция all() возвращает True, если все пары равны. Этот способ краток и не создает промежуточных строк (кроме уже очищенной).

Особенность: Данный метод также требует предварительной очистки строки. Если требуется игнорировать не только пробелы, но и знаки препинания, можно комбинировать с re.sub.

Расширенные примеры и нестандартные решения

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

Пример 1: Очистка строки с помощью filter и str.isalpha

Вместо удаления только пробелов, можно удалить все небуквенные символы, используя функцию filter.

Пример

def is_palindrome_alpha(s):
    cleaned = ''.join(filter(str.isalpha, s)).lower()
    return cleaned == cleaned[::-1]

test_str = 'A man, a plan, a canal: Panama'
result = is_palindrome_alpha(test_str)
print(result)
True

Пример 2: Числовой палиндром (без преобразования в строку)

Задача определения, является ли целое число палиндромом, решается арифметически: число переворачивается по цифрам.

Пример

def is_palindrome_number(num):
    if num < 0:
        return False
    original = num
    reversed_num = 0
    while num > 0:
        reversed_num = reversed_num * 10 + num % 10
        num //= 10
    return original == reversed_num

print(is_palindrome_number(121))
print(is_palindrome_number(12321))
print(is_palindrome_number(-121))
print(is_palindrome_number(10))
True
True
False
False

Пример 3: Использование collections.deque для сравнения с обоих концов

Двусторонняя очередь позволяет эффективно извлекать элементы с начала и конца одновременно.

Пример

from collections import deque

def is_palindrome_deque(s):
    dq = deque(s.lower().replace(' ', ''))
    while len(dq) > 1:
        if dq.popleft() != dq.pop():
            return False
    return True

print(is_palindrome_deque('racecar'))
print(is_palindrome_deque('hello'))
True
False

Пример 4: Регулярное выражение для гибкой очистки

Модуль re позволяет точно задать, какие символы оставить. В примере оставлены только буквы и цифры.

Пример

import re

def is_palindrome_regex(s):
    cleaned = re.sub(r'[^a-zA-Z0-9]', '', s).lower()
    return cleaned == cleaned[::-1]

tests = ['No x in Nixon', 'Was it a car or a cat I saw', '12321']
for t in tests:
    print(is_palindrome_regex(t))
True
True
True

Пример 5: Однострочное решение с all() и reversed()

Для любителей кратких конструкций подходит вариант с использованием генератора.

Пример

def is_palindrome_oneline(s):
    s = ''.join(filter(str.isalpha, s)).lower()
    return all(a == b for a, b in zip(s, reversed(s)))

print(is_palindrome_oneline('Madam, I\'m Adam'))
True

Пример 6: Проверка палиндрома с игнорированием юникодных символов (нормализация)

Для строк с акцентами или другими диакритическими знаками применяется нормализация в форму NFKD и удаление комбинирующих символов.

Пример

import unicodedata
import re

def is_palindrome_unicode(s):
    nfkd = unicodedata.normalize('NFKD', s)
    cleaned = re.sub(r'[^a-zA-Z]', '', nfkd).lower()
    return cleaned == cleaned[::-1]

test_unicode = 'Able was I ere I saw Elba'
print(is_palindrome_unicode(test_unicode))
True

задачи по Python - comments

En
программы python задачи (python)