Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,4 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/

assets/extra/
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Ключевые особенности

- **14** разобранных тем, к каждой теме легкий конспект
- **15+** разобранных тем, к каждой теме легкий конспект
- **70+** практических задач с LeetCode, тренировок от Яндекса и реальных собеседований
- Решение **к каждой задаче** на лаконичном Python с комментариями
- **800+** автоматизированных тестов для проверки решений
Expand All @@ -26,7 +26,8 @@
| 11 | Теория чисел | Продвинутые подходы | `k_number_theory` |
| 12 | 2D Динамическое программирование | Продвинутые подходы | `l_dp2` |
| 13 | Деревья | Продвинутые структуры данных | `m_trees` |
| 14 | Графы | Продвинутые структуры данных | `n_trees` |
| 14 | Кучи | Продвинутые структуры данных | `n_heaps` |
| 15 | Графы | Продвинутые структуры данных | `o_trees` |

Каждая тема содержит:

Expand Down
188 changes: 188 additions & 0 deletions src/n_heaps/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Задачи на кучи

## A. Построение кучи

| Поле | Значение |
|-----------|---------------------------------------------------|
| Сложность | Легкая |
| Источник | https://stepik.org/lesson/41560/step/1?unit=20013 |

Переставить элементы заданного массива чисел так, чтобы он удовлетворял свойствам мин-кучи.

Формат входа. В первой строке задано число N (1 ≤ N ≤ 10^5) — количество элементов в массиве. Во второй
строке задано N целых чисел, разделенных пробелами — элементы массива. Все числа по модулю не превосходят 10^9.

Формат выхода. В первой строке выведите число S — количество перестановок, которые необходимо сделать, чтобы
превратить массив в мин-кучу. В следующих S строках выведите по одной перестановке в формате "i j", где i и j — индексы
элементов, которые нужно поменять местами. Индексация элементов массива начинается с нуля.

Пример.
Ввод:

```text
5
5 4 3 2 1
```

Вывод:

```text
3
1 4
0 1
1 3
```

## B. Очередь с приоритетом

| Поле | Значение |
|-----------|--------------------------------------------------|
| Сложность | Легкая |
| Источник | https://stepik.org/lesson/13240/step/8?unit=3426 |

Реализуйте структуру данных "очередь с приоритетом" на основе кучи. Ваша очередь должна поддерживать следующие
операции:

- insert(x) - вставить элемент x в очередь с приоритетом
- extract_max() - извлечь элемент с максимальным приоритетом из очереди с приоритетом и вывести его. Гарантируется, что
очередь с приоритетом не будет пустой в момент вызова операции extract_max().

Формат входа. В первой строке число N (1 ≤ N ≤ 10^5) — количество операций. В каждой из следующих N строк записано
описание операции. Операция insert(x) задается строкой "Insert x", где x — целое число, по модулю не превосходящее 10^9.
Операция extract_max() задается строкой "ExtractMax".

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

Пример.

Ввод:

```text
6
Insert 200
Insert 10
ExtractMax
Insert 5
Insert 500
ExtractMax
```

Вывод:

```text
200
500
```

## С. Сортировка массива

| Поле | Значение |
|-----------|----------------------------------------------------------|
| Сложность | Средняя |
| Источник | https://leetcode.com/problems/sort-an-array/description/ |

## D. Кодирование строки

| Поле | Значение |
|-----------|----------------------------------------|
| Сложность | Средняя |
| Источник | https://stepik.org/lesson/13239/step/5 |

Дана строка из строчных букв латинского алфавита. Закодируйте строку с помощью алгоритма Хаффмана.

Формат входа. Строка, которую нужно закодировать. Длина строки не превосходит 10^4.

Формат выхода. В первой строке выведите количество различных букв K, встречающихся в строке, и размер получившейся
закодированной
строки. В следующих K строках запишите коды букв в формате "letter: code". В последней строке выведите закодированную
строку.

Пример.

Ввод:

```text
abacabad
```

Вывод:

```text
4 14
a: 0
b: 10
c: 110
d: 111
01001100100111
```

## E. Параллельная обработка

| Поле | Значение |
|-----------|---------------------------------------------------|
| Сложность | Средняя |
| Источник | https://stepik.org/lesson/41560/step/2?unit=20013 |

По данным n процессорам и m задачам определите, для каждой из задач,
каким процессором она будет обработана.

Формат входа. В первой строке заданы два целых числа n и m (1 ≤ n ≤ 10^5, 1 ≤ m ≤ 10^5) — количество процессоров и
задач. Во второй строке задано m целых чисел t_i (0 ≤ t_i ≤ 10^9) — время, необходимое для обработки i-й задачи.

Формат выхода. Выведите m строк. В i-й строке должно быть указано, каким процессором будет обработана i-я задача и в
какое время она начнет обрабатываться. Процессоры нумеруются от 0 до n-1. Если несколько процессоров свободны в момент
начала обработки задачи, выберите процессор с наименьшим номером.

Пример 1.

Ввод:

```text
2 5
1 2 3 4 5
```

Вывод:

```text
0 0
1 0
0 1
1 2
0 4
```

Пример 2.

Ввод:

```text
4 20
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
```

Вывод:

```text
0 0
1 0
2 0
3 0
0 1
1 1
2 1
3 1
0 2
1 2
2 2
3 2
0 3
1 3
2 3
3 3
0 4
1 4
2 4
3 4
```
File renamed without changes.
45 changes: 45 additions & 0 deletions src/n_heaps/heap_sort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# сортировка кучей - O(NlogN)
import heapq


def heap_sort(a: list[int]) -> list[int]:
n = len(a)
h: list[int] = []
for i in range(n):
heapq.heappush(h, a[i])
return [heapq.heappop(h) for _ in range(n)]


# просеивание вниз - O(logN)
def sift_down(a: list[int], size: int, i: int) -> None:
while 2 * i + 1 < size:
# потомки вершины i
left = 2 * i + 1
right = 2 * i + 2
# берём максимум из потомков
j = left
if right < size and a[right] > a[left]:
j = right
# если текущий элемент больше или равен потомка,
# значит он располагается правильно - выходим
if a[i] >= a[j]:
break
a[i], a[j] = a[j], a[i]
i = j


# построение кучи - O(N)
def build_heap(a: list[int], size: int) -> None:
for i in range(size // 2, -1, -1):
sift_down(a, size, i)


# сортировка кучей на месте - O(NlogN)
def heap_sort_inplace(a: list[int]) -> None:
n = len(a)
build_heap(a, n)
size = n
for _i in range(n, 1, -1):
a[size - 1], a[0] = a[0], a[size - 1]
size -= 1
sift_down(a, size, 0)
21 changes: 21 additions & 0 deletions src/n_heaps/heapify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
def sift_down(a: list[int], size: int, i: int) -> list[tuple[int, int]]:
swaps: list[tuple[int, int]] = []
while 2 * i + 1 < size:
left = 2 * i + 1
right = 2 * i + 2
j = left
if right < size and a[right] < a[left]:
j = right
if a[i] <= a[j]:
break
a[i], a[j] = a[j], a[i]
swaps.append((i, j))
i = j
return swaps


def heapify(size: int, a: list[int]) -> list[tuple[int, int]]:
swaps: list[tuple[int, int]] = []
for i in range(size // 2, -1, -1):
swaps += sift_down(a, size, i)
return swaps
66 changes: 66 additions & 0 deletions src/n_heaps/huffman.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import heapq


# O(n log n)
def huffman_encode(s: str) -> tuple[str, dict[str, str]]:
result = ""
tree = huffman_tree(s)
for c in s:
result += tree[c]
return result, tree


# O(n)
def huffman_decode(s: str, tree: dict[str, str]) -> str:
result = ""
code = ""
for c in s:
code += c
if code in tree:
result += tree[code]
code = ""
return result


# O(n log n)
def huffman_tree(s: str) -> dict[str, str]:
# Считаем частоту встречаемости каждого символа в строке.
freq = count_chars(s)
# Создаем кучу: каждый элемент очереди представляет собой кортеж (частота, символ).
queue = [(v, k) for k, v in freq.items()]
heapq.heapify(queue)
# Создаем словарь для хранения кодов Хаффмана.
tree = {c: "" for c in freq}
# Если в строке есть только один символ, то кодируем его как "0".
if len(freq) == 1:
tree[s[0]] = "0"
# Пока в очереди есть хотя бы два узла.
while len(queue) >= 2:
# Извлекаем два узла с минимальной частотой - их нужно закодировать в первую очередь.
left = extract_min(queue)
right = extract_min(queue)
# Добавляем новый узел в очередь:
# его название равно конкатенации названий двух извлеченных узлов (a + b = ab),
# а его частота равна сумме частот двух извлеченных узлов (1 + 2 = 3).
queue.append((left[0] + right[0], left[1] + right[1]))
# Обновляем предков: добавляем "0" к коду левого узла и "1" к коду правого узла.
for ancestor in left[1]:
tree[ancestor] = "0" + tree[ancestor]
for ancestor in right[1]:
tree[ancestor] = "1" + tree[ancestor]
return tree


# O(n)
def count_chars(s: str) -> dict[str, int]:
freq = {}
for c in s:
if c not in freq:
freq[c] = 0
freq[c] += 1
return freq


# O(log n)
def extract_min(queue: list[tuple[int, str]]) -> tuple[int, str]:
return heapq.heappop(queue)
14 changes: 14 additions & 0 deletions src/n_heaps/parallel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import heapq


def parallel(n: int, m: int, time: list[int]) -> list[tuple[int, int]]:
result = []
h: list[tuple[int, int]] = []
for i in range(n):
heapq.heappush(h, (0, i))
for i in range(m):
t = time[i]
x = heapq.heappop(h)
result.append((x[1], x[0]))
heapq.heappush(h, (x[0] + t, x[1]))
return result
Loading
Loading