Задачи по Python с решениями: типовые задачи с собеседований
Одно дело знать синтаксис Python, другое, уметь писать на нём коротко и по делу. На джуниорском собесе часто дают маленькую практическую задачу и смотрят не на то, решите ли вы её вообще, а на то, решите ли по-питоновски. Развернуть список циклом на пять строк или срезом в один символ. Считать частоты руками или через Counter. Разница между «пишет на Python» и «пишет как на Java со словами Python».
Ниже типовые задачи по темам, с решениями и разбором, что в них проверяют. Все примеры рабочие, диалект обычный CPython.
Строки и списки
Развернуть строку. Классический первый вопрос. Питоничный ответ, это срез с шагом −1, без всякого цикла:
s = "собес"
s[::-1] # 'себос'
Проверить палиндром. Строится на том же срезе:
def is_palindrome(s):
s = s.lower()
return s == s[::-1]
Анаграммы. Две строки будут анаграммами, если состоят из одних букв в разном порядке. Решают либо сортировкой, либо счётчиком символов:
from collections import Counter
def is_anagram(a, b):
return Counter(a) == Counter(b)
Сортировка sorted(a) == sorted(b) тоже работает, но это O(n log n), а Counter за O(n). Хороший повод проговорить сложность вслух.
Словари и Counter
Самое частое слово в тексте. Задача, которую дают почти всем. Руками через dict можно, но Counter делает это в одну строку:
from collections import Counter
words = text.split()
Counter(words).most_common(1) # [('и', 42)]
Группировка по ключу. Разложить пары по группам. Питоничный инструмент, это defaultdict, чтобы не проверять наличие ключа вручную:
from collections import defaultdict
groups = defaultdict(list)
for name, dept in employees:
groups[dept].append(name)
Словарь из двух списков. zip плюс dict, знание которого проверяют постоянно:
dict(zip(keys, values))
Множества
Убрать дубликаты, сохранив порядок. Ловушка: set(items) дубликаты уберёт, но порядок потеряет. Питоничный трюк, через dict.fromkeys, который порядок помнит:
list(dict.fromkeys(items)) # порядок сохранён, дубли убраны
Общие элементы двух списков. Пересечение множеств за O(n) вместо вложенного цикла:
set(a) & set(b)
Заодно спросят, почему проверка x in set(...) быстрее, чем x in list(...): множество на хеш-таблице даёт в среднем O(1), а список O(n).
Генераторы
Числа Фибоначчи потоком. Генератор отдаёт значения по одному и не хранит всё в памяти, поэтому им можно получать сколько угодно чисел:
def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
yield превращает функцию в генератор. Спросят, чем это лучше списка: список надо посчитать целиком и держать в памяти, а генератор ленив и бесконечен.
Классика с подвохом
FizzBuzz. Куда без него. Числа от 1 до n: кратные 3 дают «Fizz», кратные 5 «Buzz», кратные обоим «FizzBuzz». Проверяют не логику, а чистоту кода:
for i in range(1, n + 1):
print("Fizz" * (i % 3 == 0) + "Buzz" * (i % 5 == 0) or i)
Развернуть вложенный список (flatten). Рекурсией или через генератор. Заодно проверят, понимаете ли вы рекурсию:
def flatten(lst):
for x in lst:
if isinstance(x, list):
yield from flatten(x)
else:
yield x
И почти наверняка где-то всплывёт изменяемый аргумент по умолчанию (def f(x=[])), самая известная ловушка Python. Разбор этой и других теоретических каверз, в посте про вопросы на собеседовании Python.
Как готовиться
Такие задачи ставятся руками и повторением: один раз написал dict.fromkeys для дедупа, запомнил навсегда. Читать решения бесполезно, надо решать самому, ошибаться и переписывать короче.
В Сеньорчике задачи и вопросы по Python идут короткими сессиями с разбором внутри треков Data Science и аналитики, а движок возвращает темы, где вы плывёте. Если готовитесь к алгоритмической секции биг-теха, там нужны не идиомы, а паттерны, их разбирает пост про литкод. Начать можно бесплатно.