Python тестовое задание: как успешно решить задачу на палиндром
Разбор типового тестового задания: проверка строки на палиндром
Наиболее эффективное решение
Для проверки, является ли строка палиндромом, оптимально использовать сравнение с обратной версией строки после нормализации. Этот подход имеет сложность O(n) по времени и O(n) по памяти (на создание обратной строки).
def is_palindrome(s: str) -> bool:
"""Проверяет, является ли строка палиндромом (без учёта регистра)."""
# Нормализация: приводим к нижнему регистру
normalized = s.lower()
# Сравниваем с обратной строкой
return normalized == normalized[::-1]яндекс задания python (задания от яндекса по python)
# Пример использования
print(is_palindrome("Racecar")) # True
print(is_palindrome("Python")) # FalsePython разработчик тестовые задания (примеры тестовых заданий python)
Пояснение: метод [::-1] создаёт срез с шагом -1, что даёт строку в обратном порядке. Сравнение выполняется поэлементно. Нормализация через lower() позволяет игнорировать регистр.
Как проверить палиндром без использования срезов?
Если по условию запрещено использовать срезы или требуется показать понимание алгоритма, можно применить цикл с двумя указателями.
def is_palindrome_two_pointers(s: str) -> bool:
"""Проверка двумя указателями."""
left, right = 0, len(s) - 1
while left < right:
if s[left].lower() != s[right].lower():
return False
left += 1
right -= 1
return Trueегэ python задачи (задачи егэ по python)
print(is_palindrome_two_pointers("Aba")) # True
print(is_palindrome_two_pointers("Hello")) # Falseрешу егэ python (решение заданий егэ по python)
Проблема: при очень длинных строках цикл может быть медленным, но это незначительно. Типичная ошибка: забыть про приведение к нижнему регистру.
Как реализовать рекурсивную проверку палиндрома?
Рекурсивный подход нагляден, но неэффективен для длинных строк из-за переполнения стека.
def is_palindrome_recursive(s: str) -> bool:
"""Рекурсивная проверка."""
if len(s) <= 1:
return True
if s[0].lower() != s[-1].lower():
return False
return is_palindrome_recursive(s[1:-1])Python тестовое (тестовое задание python)
print(is_palindrome_recursive("Level")) # True
print(is_palindrome_recursive("Test")) # Falseзадачи огэ python (задачи огэ по python)
Проблемы: глубина рекурсии не может превышать лимит (обычно 1000), поэтому для строк длиннее 500 символов возможна ошибка. Решение: использовать итеративный вариант или увеличить лимит через sys.setrecursionlimit.
Как проверить палиндром с учётом пробелов и знаков препинания?
Часто в тестовых заданиях требуется игнорировать все небуквенные символы. Например, фраза "А роза упала на лапу Азора" считается палиндромом.
import re
def is_palindrome_cleaned(s: str) -> bool:
"""Проверка после удаления небуквенных символов."""
# Оставляем только буквы и цифры (можно и только буквы)
cleaned = re.sub(r'[^a-zA-Zа-яА-Я0-9]', '', s).lower()
return cleaned == cleaned[::-1]задачи python 9 класс (задачи по python для 9 класса)
print(is_palindrome_cleaned("A man, a plan, a canal: Panama")) # True
print(is_palindrome_cleaned("А роза упала на лапу Азора")) # Trueолимпиады python задачи (олимпиадные задачи по python)
Проблема: регулярное выражение создаёт дополнительную строку и может быть медленным на больших текстах. Альтернатива: использовать filter(str.isalnum, s) или вручную проверять каждый символ.
Как проверить палиндром без дополнительной памяти?
Если требуется константная память O(1), можно использовать два указателя, пропуская небуквенные символы на ходу.
def is_palindrome_inplace(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егэ информатика 19 задание python (19 задание егэ по информатике на python)
print(is_palindrome_inplace("Was it a car or a cat I saw?")) # True
print(is_palindrome_inplace("No 'x' in Nixon.")) # True
Проблема: нужно аккуратно управлять указателями, чтобы не выйти за границы. Типичная ошибка: бесконечный цикл, если все символы небуквенные (но условие left < right остановит).
Типичные проблемы и способы их решения
- Проблема: Не учитывается регистр. Решение: Обязательно приводить строку к одному регистру (lower() или casefold() для лучшей обработки Unicode).
- Проблема: Пустая строка или строка из одного символа. Решение: Такие строки являются палиндромами по определению - алгоритмы должны возвращать True.
- Проблема: Строка содержит символы Unicode (например, эмодзи, акценты). Решение: Использовать casefold() вместо lower() и unicodedata.normalize() для приведения к общему виду.
- Проблема: Переполнение стека при рекурсии для длинных строк. Решение: Выбирать итеративные алгоритмы.
- Проблема: Некорректное удаление пробелов и знаков препинания (например, апострофы или дефисы). Решение: Определить чёткий список символов, которые считаются значимыми (цифры, буквы).
Расширенные примеры и углублённые техники
Пример 1. Проверка палиндрома с обработкой Unicode (французские акценты)
import unicodedata
def is_palindrome_unicode(s: str) -> bool:
# Удаляем диакритические знаки
nfkd = unicodedata.normalize('NFKD', s)
ascii_str = nfkd.encode('ASCII', 'ignore').decode('ASCII')
cleaned = ''.join(filter(str.isalnum, ascii_str)).lower()
return cleaned == cleaned[::-1]
print(is_palindrome_unicode("Élevé")) # False, так как "elev" не палиндром
print(is_palindrome_unicode("Racecar")) # True
False True
Пример 2. Проверка палиндрома для чисел (задача из LeetCode)
def is_palindrome_number(x: int) -> bool:
# Отрицательные числа не могут быть палиндромами
if x < 0 or (x % 10 == 0 and x != 0):
return False
reversed_half = 0
while x > reversed_half:
reversed_half = reversed_half * 10 + x % 10
x //= 10
# Для чётного и нечётного количества цифр
return x == reversed_half or x == reversed_half // 10
print(is_palindrome_number(121)) # True
print(is_palindrome_number(-121)) # False
print(is_palindrome_number(10)) # False
True False False
Пример 3. Палиндром с использованием стека
def is_palindrome_stack(s: str) -> bool:
stack = []
# помещаем первую половину символов в стек
length = len(s)
for i in range(length // 2):
stack.append(s[i].lower())
# сравниваем со второй половиной (для нечётной длины пропускаем средний)
start = length // 2 + (length % 2)
for i in range(start, length):
if s[i].lower() != stack.pop():
return False
return True
print(is_palindrome_stack("Racecar")) # True
print(is_palindrome_stack("Python")) # False
True False
Пример 4. Сравнение производительности разных методов (timeit)
import timeit
test_str = "A man, a plan, a canal, Panama!" * 100
time_slice = timeit.timeit(lambda: is_palindrome_cleaned(test_str), number=100)
time_pointers = timeit.timeit(lambda: is_palindrome_inplace(test_str), number=100)
print(f"Срез с regex: {time_slice:.4f} сек")
print(f"Два указателя in-place: {time_pointers:.4f} сек")
Срез с regex: 0.0254 сек Два указателя in-place: 0.0123 сек
Пример 5. Проверка палиндрома для связного списка (задача для собеседования)
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def is_palindrome_linked_list(head: ListNode) -> bool:
# Находим середину списка (метод двух указателей)
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# Переворачиваем вторую половину
prev = None
while slow:
nxt = slow.next
slow.next = prev
prev = slow
slow = nxt
# Сравниваем с первой половиной
left, right = head, prev
while right:
if left.val != right.val:
return False
left = left.next
right = right.next
return True
# Создаём список [1->2->2->1]
head = ListNode(1, ListNode(2, ListNode(2, ListNode(1))))
print(is_palindrome_linked_list(head)) # True
True