Prosto Python | вопросы с собесов
363 subscribers
184 photos
1 video
2 files
563 links
🚀 Python-собесы без сюрпризов! Разбираем реальные вопросы, ошибки кандидатов и лайфхаки, которые помогают пройти интервью. Джун → мидл → сеньор — прокачивайся и разнеси следующий собес! 🔥
Download Telegram
Rookie Mistakes
Тема: путаница с изменяемыми объектами при умножении списка


Перед тобой такой код:

matrix = [[0] * 3] * 3

matrix[0][0] = 1

print(matrix)


Большинство ожидает:
[[1, 0, 0],
[0, 0, 0],
[0, 0, 0]]


Но реальный вывод будет:
[[1, 0, 0],
[1, 0, 0],
[1, 0, 0]]


🧠 В чём ошибка?


[[0] * 3] * 3
не создаёт три независимых списка.

Он создаёт один список
и три ссылки на него.

Ты меняешь один элемент
и изменения отражаются во всех строках.

Правильный способ:
matrix = [[0] * 3 for _ in range(3)]
matrix[0][0] = 1
print(matrix)


Теперь каждая строка — отдельный объект


🐍Вопросы с собесов -> ProstoPython
👍4
Новая рубрика — 🧠 Interview Thinking

Здесь мы разбираем не просто задачи, а ход мыслей на собеседовании.
Как начинает рассуждать junior.
Как усиливает решение strong middle.
И какие сигналы интервьюер считывает во время ответа.

Код можно выучить.
А вот умение мыслить вслух, анализировать и улучшать своё решение — это уже уровень.


Мы стараемся постоянно придумывать новые форматы и разборы, чтобы подготовка была живой, разнообразной и максимально приближённой к реальным интервью.

Хочется, чтобы ты выходил на собес спокойным и уверенным в себе 🐍

🐍Вопросы с собесов -> ProstoPython
🔥41
🧠 Interview Thinking — выпуск 1

Тема: «Как найти цикл в связном списке?»

💬 Задача с собеса:
Дан head односвязного списка. Нужно определить, есть ли в нём цикл.

👶 Junior думает так:

«Буду сохранять все посещённые узлы в set.
Если узел уже встречался — значит цикл».

Работает? Да.
Сложность O(n).
Память O(n).

Нормально. Но не максимум.

🧑‍💻 Strong Middle думает глубже:

«Если есть цикл, можно использовать два указателя.
Один двигается на 1 шаг, второй на 2.
Если они встретятся — цикл есть».

Без дополнительной памяти.
Сложность O(n).
Память O(1).

🧠 Что реально хочет услышать интервьюер:

🔹Ты сначала предлагаешь рабочее решение

🔹Потом сам улучшаешь его

🔹Объясняешь trade-off по памяти

🐍Вопросы с собесов -> ProstoPython
👍4
CRUD — базовые операции над данными:

🔹 Create — создание новой записи в системе
🔹 Read — получение одной или нескольких записей
🔹 Update — изменение существующей записи
🔹 Delete — удаление записи

CRUD лежит в основе:
🔹 REST API
🔹 SQL-запросов
🔹 большинства backend-приложений

🐍Вопросы с собесов -> ProstoPython
🔥4
Новая рубрика — 📈 From O(n²) to O(n) — выпуск 1

Здесь мы берём рабочий, но неоптимальный код — и делаем его быстрее.

Цель простая: научиться видеть, где алгоритм «тормозит», и прокачать алгоритмическое мышление.

💬 Задача:
Проверить, есть ли в списке дубликаты.

Наивное решение:
def has_duplicates(nums):
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] == nums[j]:
return True
return False


Работает? Да.
Сложность? O(n²).


Два вложенных цикла.
На больших данных будет больно.

Улучшаем до O(n):
def has_duplicates(nums):
seen = set()
for num in nums:
if num in seen:
return True
seen.add(num)
return False


Теперь:
Проверка в set — O(1)
Один проход — O(n)

Итого O(n).

🧠 Что прокачиваем в этой рубрике:

🔹 умение замечать лишние вложенные проходы
🔹 понимание структур данных
🔹 привычку думать про масштабирование

🐍Вопросы с собесов -> ProstoPython
🏆6
⏱️ Big O Breakdown

Посмотри на код:
def strange(n):
i = n
while i > 1:
for j in range(i):
print(j)
i //= 2


Какая сложность?

A) O(n)
B) O(log n)
C) O(n log n)
D) O(n²)

Правильный ответ: A) O(n)

Да, не O(n log n). И вот почему 👇

🧠 Разбираем пошагово:

Первая итерация:
цикл на n операций

Вторая:
n/2

Третья:
n/4

Потом:
n/8
и так далее…

Суммарно получаем:

n + n/2 + n/4 + n/8 + ...

Это убывающая геометрическая прогрессия.
Её сумма стремится к 2n.

А значит итоговая сложность — O(n).

🐍Вопросы с собесов -> ProstoPython
👍4
Попробуйте ответить без запуска, что выведет код, разбор будет через 2 часа

🐍Вопросы с собесов -> ProstoPython
Правильный ответ: [1, 2, 3, 4]

🧠 Разбираем:

Строка:

lst += [4]

Для списка это in-place изменение.
Объект x действительно меняется.


А вот дальше:


lst = [0]

Это уже просто переопределение локальной переменной lst.
К исходному списку x это отношения не имеет.

Именно поэтому:

x стал [1, 2, 3, 4]

🔹присваивание [0] не повлияло на него

🐍Вопросы с собесов -> ProstoPython
👍5
Коллизия — ситуация, когда разные ключи дают одинаковый хеш или попадают в один индекс хеш-таблицы.

Как обходится

Open Addressing (открытая адресация)

🔹 Если ячейка занята — ищется следующая свободная

Используются стратегии:

🔹линейное пробирование

🔹квадратичное

🔹двойное хеширование

Так работает dict в Python.


🐍Вопросы с собесов -> ProstoPython
🔥4
📈 From O(n²) to O(n)
Задача: найти два числа в массиве, сумма которых равна target


Это одна из классических задач, которую очень любят на Python-собеседованиях.

Неоптимальное решение — O(n²)
nums = [3, 7, 2, 9, 7, 5]
target = 14

for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
print(i, j)


Идея простая:
для каждого элемента проверяем все остальные.

Работает.
Но у такого решения квадратичная сложность O(n²).


Если элементов станет много, программа начнёт работать заметно медленнее.

Оптимальное решение — O(n)

nums = [3, 7, 2, 9, 7, 5]
target = 14
seen = {}

for i, num in enumerate(nums):
need = target - num
if need in seen:
print(seen[need], i)
seen[num] = i


🧠 Что изменилось

🔹 массив проходим только один раз
🔹 используем словарь (hash map) для хранения уже просмотренных чисел
🔹 проверка in dict работает за O(1)

В итоге получаем линейную сложность O(n) вместо O(n²).

🐍Вопросы с собесов -> ProstoPython
👍41
Rookie Mistakes

Тема: изменяемый объект как значение по умолчанию

Это одна из самых коварных ошибок в Python.
Многие новички даже не подозревают, что здесь происходит.


Ошибка
def add_item(item, items=[]):
items.append(item)
return items

print(add_item(1))
print(add_item(2))
print(add_item(3))


На первый взгляд кажется, что функция каждый раз создаёт новый список.

Но вывод будет такой:
[1]
[1, 2]
[1, 2, 3]


🧠 Почему так происходит

Значения по умолчанию в Python создаются один раз — в момент определения функции, а не при каждом вызове.

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


Правильный вариант
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items

print(add_item(1))
print(add_item(2))
print(add_item(3))


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

🐍Вопросы с собесов -> ProstoPython
👍4🏆1
В Python используется модель call by object reference (передача ссылки на объект).

Это означает:

🔹 В функцию передаётся ссылка на объект
🔹 Но сама ссылка передаётся по значению

в Python аргументы передаются по ссылке на объект, но переприсваивание внутри функции не влияет на внешний объект

🐍Вопросы с собесов -> ProstoPython
👍3
⏱️ Big O Breakdown

Разберём пример.
import math

n = 1000000
i = 1

while i * i <= n:
i += 1


Вопрос: какая здесь временная сложность?

A) O(n)
B) O(log n)
C) O(√n)
D) O(n²)

Ответ: O(√n)

🧠 Разбор

Цикл работает, пока выполняется условие:

i * i <= n


Это то же самое что:

i <= √n


То есть переменная i увеличится примерно до корня из n.

Если n = 1 000 000,
цикл выполнится примерно 1000 раз, а не миллион.


🐍Вопросы с собесов -> ProstoPython
👍5
Оконные функции — функции SQL, которые выполняют вычисления по группе строк (окну), при этом не объединяют строки в одну, как это делает GROUP BY.

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

Как задаётся окно

🔹 PARTITION BY — разбивает данные на группы
🔹 ORDER BY — задаёт порядок внутри группы

Частые функции

🔹 ROW_NUMBER() — нумерация строк
🔹 RANK() — ранжирование
🔹 SUM() / AVG() — агрегаты по окну
🔹 LAG() / LEAD() — доступ к соседним строкам

🐍Вопросы с собесов -> ProstoPython
🔥5
📈 From O(n²) to O(n)
Задача: проверить, есть ли в строке повторяющиеся символы


Очень частая задача на собеседованиях.

Наивное решение — O(n²)

def has_duplicates(s):
for i in range(len(s)):
for j in range(i + 1, len(s)):
if s[i] == s[j]:
return True
return False


Логика простая:
каждый символ сравниваем со всеми остальными.

Работает.
Но это два вложенных цикла —> O(n²).

На длинных строках будет медленно.

Оптимальное решение — O(n)
def has_duplicates(s):
seen = set()

for char in s:
if char in seen:
return True
seen.add(char)

return False


🧠 Что изменилось

🔹 строку проходим один раз
🔹 используем set для хранения символов
🔹 проверка in set работает за O(1)

В итоге вся функция работает за O(n).

🐍Вопросы с собесов -> ProstoPython
👍4
⏱️ Big O Breakdown

Посмотри на код:
def process(n):
i = 1
while i < n:
for j in range(i):
print(j)
i *= 2


Какая сложность?

A) O(n)
B) O(n log n)
C) O(log n)
D) O(n²)

Правильный ответ: A) O(n)

🧠 Разбираем

Значение i растёт так:

1
2
4
8
16
...


То есть цикл выполняется log n раз.

Но внутренний цикл каждый раз работает:

1
2
4
8
16
...

Если сложить все итерации:

1 + 2 + 4 + 8 + ... + n

Это геометрическая прогрессия.

Её сумма примерно 2n

📌 Итог

Общее количество операций примерно 2n

А значит итоговая сложность:

O(n)


🐍Вопросы с собесов -> ProstoPython
👍6
Попробуйте ответить без запуска, что выведет код, разбор будет через 2 часа

🐍Вопросы с собесов -> ProstoPython
🔥2
Что выведет код выше?
Anonymous Poll
13%
[1, 2, 3]
57%
[1, 3]
13%
[1, 2]
17%
Ошибка
Разбор по шагам:

1️⃣ Список изначально

[1, 2, 3]

2️⃣ Первая итерация
i = 1
ничего не происходит.

3️⃣ Вторая итерация
i = 2
выполняется:

x.remove(2)

Список становится:

[1, 3]

4️⃣ Итератор пытается перейти к следующему индексу,
но список уже сократился, поэтому цикл завершается.


Итог:

[1, 3]


🐍Вопросы с собесов -> ProstoPython
👍5
🧰 Code Cleanup — выпуск 27
Тема: лишний else после return


Иногда код работает нормально, но читается тяжелее, чем должен.

Плохо:
def check_age(age):
if age >= 18:
return "adult"
else:
return "minor"


Функция работает.
Но else здесь вообще не нужен.


Code Cleanup:
def check_age(age):
if age >= 18:
return "adult"
return "minor"


🧠 Почему так лучше


🔹 код короче
🔹 меньше уровней вложенности
🔹 читается быстрее
🔹 легче поддерживать

После return выполнение функции и так заканчивается,
поэтому else становится лишним.


🐍Вопросы с собесов -> ProstoPython
🔥5