fix Ru translation (#1894)

* docs(ru): replace prose quotes with guillemets

* docs(ru): replace prose semicolons with periods

* docs(ru): align animation title forms

* docs(ru): align figure and table references
This commit is contained in:
Yudong Jin
2026-04-14 18:10:12 +08:00
committed by GitHub
parent 1d12e2def5
commit 22b3b568ef
94 changed files with 565 additions and 570 deletions
@@ -5,36 +5,36 @@
- **Полный перебор**: реализуется через обход структуры данных, временная сложность равна $O(n)$ .
- **Адаптивный поиск**: использует особую организацию данных или априорную информацию, временная сложность может достигать $O(\log n)$ и даже $O(1)$ .
На практике **алгоритмы поиска с временной сложностью $O(\log n)$ обычно реализуются на основе стратегии "разделяй и властвуй"**, например двоичный поиск и деревья.
На практике **алгоритмы поиска с временной сложностью $O(\log n)$ обычно реализуются на основе стратегии «разделяй и властвуй»**, например двоичный поиск и деревья.
- На каждом шаге двоичный поиск раскладывает задачу (поиск целевого элемента в массиве) на более мелкую задачу (поиск целевого элемента в одной половине массива), и этот процесс продолжается, пока массив не станет пустым или пока не будет найден целевой элемент.
- Деревья являются типичными представителями идей "разделяй и властвуй"; в таких структурах данных, как двоичное дерево поиска, AVL-дерево и куча, временная сложность различных операций равна $O(\log n)$ .
- Деревья являются типичными представителями идей «разделяй и властвуй». В таких структурах данных, как двоичное дерево поиска, AVL-дерево и куча, временная сложность различных операций равна $O(\log n)$ .
Стратегия "разделяй и властвуй" для двоичного поиска выглядит следующим образом.
Стратегия «разделяй и властвуй» для двоичного поиска выглядит следующим образом.
- **Задача раскладывается на части**: двоичный поиск рекурсивно разбивает исходную задачу (поиск в массиве) на подзадачу (поиск в одной половине массива), и это достигается сравнением среднего элемента с целевым значением.
- **Подзадачи независимы**: в двоичном поиске на каждом шаге обрабатывается только одна подзадача, и она не зависит от других подзадач.
- **Решения подзадач не нужно объединять**: двоичный поиск нацелен на поиск конкретного элемента, поэтому объединять решения подзадач не требуется. Как только подзадача решена, одновременно считается решенной и исходная задача.
Иными словами, стратегия "разделяй и властвуй" повышает эффективность поиска потому, что при полном переборе за один шаг удается исключить только один вариант, **тогда как при поиске на основе "разделяй и властвуй" за один шаг можно исключить половину вариантов**.
Иными словами, стратегия «разделяй и властвуй» повышает эффективность поиска потому, что при полном переборе за один шаг удается исключить только один вариант, **тогда как при поиске на основе «разделяй и властвуй» за один шаг можно исключить половину вариантов**.
### Реализация двоичного поиска на основе "разделяй и властвуй"
### Реализация двоичного поиска на основе «разделяй и властвуй»
В предыдущих главах двоичный поиск реализовывался через итерацию. Теперь реализуем его с помощью стратегии "разделяй и властвуй", то есть через рекурсию.
В предыдущих главах двоичный поиск реализовывался через итерацию. Теперь реализуем его с помощью стратегии «разделяй и властвуй», то есть через рекурсию.
!!! question
Дан отсортированный массив `nums` длины $n$ , в котором все элементы уникальны. Найдите элемент `target` .
С точки зрения стратегии "разделяй и властвуй" обозначим подзадачу, соответствующую интервалу поиска $[i, j]$ , через $f(i, j)$ .
С точки зрения стратегии «разделяй и властвуй» обозначим подзадачу, соответствующую интервалу поиска $[i, j]$ , через $f(i, j)$ .
Начиная с исходной задачи $f(0, n-1)$ , выполняем двоичный поиск по следующим шагам.
1. Вычислить середину $m$ интервала поиска $[i, j]$ и с ее помощью исключить половину интервала.
2. Рекурсивно решить подзадачу вдвое меньшего размера; это может быть либо $f(i, m-1)$ , либо $f(m+1, j)$ .
2. Рекурсивно решить подзадачу вдвое меньшего размера. Это может быть либо $f(i, m-1)$ , либо $f(m+1, j)$ .
3. Повторять шаг `1.` и шаг `2.` , пока не будет найден `target` или пока интервал не станет пустым.
На рисунке ниже показан процесс применения стратегии "разделяй и властвуй" для поиска элемента $6$ в массиве.
На рисунке ниже показан процесс применения стратегии «разделяй и властвуй» для поиска элемента $6$ в массиве.
![Процесс двоичного поиска в стиле разделяй и властвуй](binary_search_recur.assets/binary_search_recur.png)
@@ -6,27 +6,27 @@
![Пример данных для построения двоичного дерева](build_binary_tree_problem.assets/build_tree_example.png)
### Проверка, является ли это задачей "разделяй и властвуй"
### Проверка, является ли это задачей «разделяй и властвуй»
Исходная задача - построить двоичное дерево по `preorder` и `inorder` - является типичной задачей для стратегии "разделяй и властвуй".
Исходная задача - построить двоичное дерево по `preorder` и `inorder` - является типичной задачей для стратегии «разделяй и властвуй».
- **Задача раскладывается на части**: если смотреть с точки зрения стратегии "разделяй и властвуй", исходную задачу можно разбить на две подзадачи: построение левого поддерева и построение правого поддерева, плюс одно действие: инициализация корневого узла. Для каждого поддерева (подзадачи) можно использовать тот же способ разбиения, пока не будет достигнута наименьшая подзадача (пустое поддерево).
- **Задача раскладывается на части**: если смотреть с точки зрения стратегии «разделяй и властвуй», исходную задачу можно разбить на две подзадачи: построение левого поддерева и построение правого поддерева, плюс одно действие: инициализация корневого узла. Для каждого поддерева (подзадачи) можно использовать тот же способ разбиения, пока не будет достигнута наименьшая подзадача (пустое поддерево).
- **Подзадачи независимы**: левое и правое поддеревья независимы друг от друга и не пересекаются. При построении левого поддерева нам нужно смотреть только на ту часть прямого и симметричного обходов, которая соответствует левому поддереву. Для правого поддерева рассуждение аналогично.
- **Решения подзадач можно объединить**: когда левое и правое поддеревья (решения подзадач) уже построены, их можно присоединить к корневому узлу и тем самым получить решение исходной задачи.
### Как разделить поддеревья
Из анализа выше видно, что эта задача действительно решается через "разделяй и властвуй", **но как именно, имея прямой обход `preorder` и симметричный обход `inorder`, отделить левое и правое поддеревья**?
Из анализа выше видно, что эта задача действительно решается через «разделяй и властвуй», **но как именно, имея прямой обход `preorder` и симметричный обход `inorder`, отделить левое и правое поддеревья**?
По определению и `preorder` , и `inorder` можно разбить на три части.
- Прямой обход: `[ корневой узел | левое поддерево | правое поддерево ]` , например для дерева на рисунке выше это `[ 3 | 9 | 2 1 7 ]` .
- Симметричный обход: `[ левое поддерево | корневой узел | правое поддерево ]` , например для дерева на рисунке выше это `[ 9 | 3 | 1 2 7 ]` .
На примере данных с рисунка можно получить результат разбиения по следующим шагам.
На примере данных на рисунке выше разбиение можно выполнить по шагам, показанным на рисунке ниже.
1. Первый элемент прямого обхода, равный 3, является значением корневого узла.
2. Найти индекс корневого узла 3 в `inorder` ; используя этот индекс, можно разбить `inorder` на `[ 9 | 3 | 1 2 7 ]` .
2. Найти индекс корневого узла 3 в `inorder`. Используя этот индекс, можно разбить `inorder` на `[ 9 | 3 | 1 2 7 ]` .
3. По результату разбиения `inorder` нетрудно определить, что число узлов в левом и правом поддеревьях равно 1 и 3 соответственно, а значит, `preorder` можно разбить как `[ 3 | 9 | 2 1 7 ]` .
![Разбиение поддеревьев в прямом и симметричном обходах](build_binary_tree_problem.assets/build_tree_preorder_inorder_division.png)
@@ -49,7 +49,7 @@
| Левое поддерево | $i + 1$ | $[l, m-1]$ |
| Правое поддерево | $i + 1 + (m - l)$ | $[m+1, r]$ |
Стоит отметить, что $(m-l)$ в индексе корневого узла правого поддерева означает число узлов в левом поддереве; лучше всего понимать это выражение вместе с рисунком ниже.
Стоит отметить, что $(m-l)$ в индексе корневого узла правого поддерева означает число узлов в левом поддереве. Лучше всего понять это выражение, сопоставив его с тем, что показано на рисунке ниже.
![Представление индексных интервалов корня и поддеревьев](build_binary_tree_problem.assets/build_tree_division_pointers.png)
@@ -61,7 +61,7 @@
[file]{build_tree}-[class]{}-[func]{build_tree}
```
На рисунке ниже показан рекурсивный процесс построения двоичного дерева: каждый узел создается в фазе "спуска", а каждое ребро (ссылка) формируется в фазе "подъема".
На рисунке ниже показан рекурсивный процесс построения двоичного дерева: каждый узел создается в фазе «спуска», а каждое ребро (ссылка) формируется в фазе «подъема».
=== "<1>"
![Рекурсивный процесс построения двоичного дерева](build_binary_tree_problem.assets/built_tree_step1.png)
@@ -94,6 +94,6 @@
![Результаты разбиения в каждом рекурсивном вызове](build_binary_tree_problem.assets/built_tree_overall.png)
Пусть число узлов дерева равно $n$ ; инициализация каждого узла (то есть выполнение одного рекурсивного вызова `dfs()` ) занимает $O(1)$ времени. **Следовательно, общая временная сложность равна $O(n)$** .
Пусть число узлов дерева равно $n$. Инициализация каждого узла (то есть выполнение одного рекурсивного вызова `dfs()` ) занимает $O(1)$ времени. **Следовательно, общая временная сложность равна $O(n)$** .
Хеш-таблица хранит отображение значений `inorder` в индексы, поэтому ее пространственная сложность равна $O(n)$ . В худшем случае, когда двоичное дерево вырождается в связный список, глубина рекурсии достигает $n$ и требует $O(n)$ памяти стека. **Следовательно, общая пространственная сложность также равна $O(n)$** .
@@ -1,20 +1,20 @@
# Стратегия разделяй и властвуй
<u>Разделяй и властвуй (divide and conquer)</u> - это очень важная и широко используемая стратегия построения алгоритмов. Обычно она реализуется через рекурсию и включает два этапа: "разделение" и "объединение".
<u>Разделяй и властвуй (divide and conquer)</u> - это очень важная и широко используемая стратегия построения алгоритмов. Обычно она реализуется через рекурсию и включает два этапа: «разделение» и «объединение».
1. **Разделение (этап декомпозиции)**: рекурсивно разбить исходную задачу на две или более подзадачи, пока не будет достигнута наименьшая подзадача.
2. **Объединение (этап синтеза)**: начиная с уже известных решений наименьших подзадач, снизу вверх объединять решения подзадач и тем самым получать решение исходной задачи.
Как показано на рисунке ниже, "сортировка слиянием" является одним из типичных примеров применения стратегии "разделяй и властвуй".
Как показано на рисунке ниже, «сортировка слиянием» является одним из типичных примеров применения стратегии «разделяй и властвуй».
1. **Разделение**: рекурсивно разделить исходный массив (исходную задачу) на два подмассива (подзадачи), пока в подмассиве не останется только один элемент (наименьшая подзадача).
2. **Объединение**: снизу вверх объединять упорядоченные подмассивы (решения подзадач), чтобы получить упорядоченный исходный массив (решение исходной задачи).
![Стратегия разделяй и властвуй в сортировке слиянием](divide_and_conquer.assets/divide_and_conquer_merge_sort.png)
## Как определить задачу "разделяй и властвуй"
## Как определить задачу «разделяй и властвуй»
Чтобы понять, подходит ли задача для решения методом "разделяй и властвуй", обычно можно ориентироваться на следующие критерии.
Чтобы понять, подходит ли задача для решения методом «разделяй и властвуй», обычно можно ориентироваться на следующие критерии.
1. **Задача раскладывается на части**: исходную задачу можно разбить на более мелкие и похожие подзадачи, причем такое разбиение можно применять рекурсивно.
2. **Подзадачи независимы**: подзадачи не пересекаются, не зависят друг от друга и могут решаться независимо.
@@ -26,15 +26,15 @@
2. **Подзадачи независимы**: каждый подмассив можно сортировать отдельно (то есть каждую подзадачу можно решать независимо).
3. **Решения подзадач можно объединить**: два упорядоченных подмассива (решения подзадач) можно объединить в один упорядоченный массив (решение исходной задачи).
## Повышение эффективности с помощью "разделяй и властвуй"
## Повышение эффективности с помощью «разделяй и властвуй»
**Стратегия "разделяй и властвуй" не только позволяет эффективно решать алгоритмические задачи, но и часто повышает эффективность самих алгоритмов**. Именно поэтому быстрая сортировка, сортировка слиянием и пирамидальная сортировка обычно работают быстрее, чем сортировка выбором, пузырьком и вставками.
**Стратегия «разделяй и властвуй» не только позволяет эффективно решать алгоритмические задачи, но и часто повышает эффективность самих алгоритмов**. Именно поэтому быстрая сортировка, сортировка слиянием и пирамидальная сортировка обычно работают быстрее, чем сортировка выбором, пузырьком и вставками.
Тогда возникает естественный вопрос: **почему стратегия "разделяй и властвуй" повышает эффективность алгоритма и какова внутренняя логика этого подхода**? Иными словами, почему разбиение большой задачи на несколько подзадач, решение этих подзадач и последующее объединение их решений оказывается эффективнее, чем прямое решение исходной задачи? Этот вопрос можно рассмотреть с двух сторон: через число операций и через параллельные вычисления.
Тогда возникает естественный вопрос: **почему стратегия «разделяй и властвуй» повышает эффективность алгоритма и какова внутренняя логика этого подхода**? Иными словами, почему разбиение большой задачи на несколько подзадач, решение этих подзадач и последующее объединение их решений оказывается эффективнее, чем прямое решение исходной задачи? Этот вопрос можно рассмотреть с двух сторон: через число операций и через параллельные вычисления.
### Оптимизация числа операций
Рассмотрим "сортировку пузырьком": для массива длины $n$ ей требуется $O(n^2)$ времени. Предположим, что мы разделим массив на два подмассива в середине, как показано на рисунке ниже. Тогда само разбиение потребует $O(n)$ времени, сортировка каждого подмассива займет $O((n / 2)^2)$ времени, а объединение двух подмассивов потребует еще $O(n)$ времени. Общая временная сложность будет равна:
Рассмотрим «сортировку пузырьком»: для массива длины $n$ ей требуется $O(n^2)$ времени. Предположим, что мы разделим массив на два подмассива в середине, как показано на рисунке ниже. Тогда само разбиение потребует $O(n)$ времени, сортировка каждого подмассива займет $O((n / 2)^2)$ времени, а объединение двух подмассивов потребует еще $O(n)$ времени. Общая временная сложность будет равна:
$$
O(n + (\frac{n}{2})^2 \times 2 + n) = O(\frac{n^2}{2} + 2n)
@@ -52,40 +52,40 @@ n(n - 4) & > 0
\end{aligned}
$$
**Это означает, что при $n > 4$ число операций после разбиения становится меньше, а значит, сортировка должна работать быстрее**. При этом важно заметить, что временная сложность после разбиения все еще остается квадратичной, то есть $O(n^2)$ ; уменьшается лишь константный множитель.
**Это означает, что при $n > 4$ число операций после разбиения становится меньше, а значит, сортировка должна работать быстрее**. При этом важно заметить, что временная сложность после разбиения все еще остается квадратичной, то есть $O(n^2)$. Уменьшается лишь константный множитель.
Если пойти дальше и **продолжать делить каждый подмассив пополам**, пока в нем не останется только один элемент, то мы фактически получим "сортировку слиянием", чья временная сложность равна $O(n \log n)$ .
Если пойти дальше и **продолжать делить каждый подмассив пополам**, пока в нем не останется только один элемент, то мы фактически получим «сортировку слиянием», чья временная сложность равна $O(n \log n)$ .
Можно пойти еще дальше и спросить: **что если задать несколько точек разделения** и равномерно разбить исходный массив на $k$ подмассивов? Такая ситуация очень похожа на блочную сортировку, которая особенно хорошо подходит для сортировки очень больших объемов данных и теоретически может достигать временной сложности $O(n + k)$ .
### Оптимизация параллельных вычислений
Мы знаем, что подзадачи, порождаемые стратегией "разделяй и властвуй", являются независимыми, **а значит, их обычно можно решать параллельно**. Иначе говоря, "разделяй и властвуй" не только может уменьшить временную сложность алгоритма, **но и хорошо сочетается с параллельной оптимизацией на уровне системы**.
Мы знаем, что подзадачи, порождаемые стратегией «разделяй и властвуй», являются независимыми, **а значит, их обычно можно решать параллельно**. Иначе говоря, «разделяй и властвуй» не только может уменьшить временную сложность алгоритма, **но и хорошо сочетается с параллельной оптимизацией на уровне системы**.
Параллельная оптимизация особенно эффективна в среде с несколькими ядрами или несколькими процессорами, потому что система может одновременно обрабатывать разные подзадачи, лучше загружая вычислительные ресурсы и тем самым заметно сокращая общее время работы.
Например, в показанной ниже "блочной сортировке" большой объем данных равномерно распределяется по блокам. Тогда сортировку каждого блока можно поручить отдельным вычислительным единицам, а после завершения просто объединить результаты.
Например, в «блочной сортировке», показанной на рисунке ниже, большой объем данных равномерно распределяется по блокам. Тогда сортировку каждого блока можно поручить отдельным вычислительным единицам, а после завершения просто объединить результаты.
![Параллельные вычисления в блочной сортировке](divide_and_conquer.assets/divide_and_conquer_parallel_computing.png)
## Типичные применения стратегии "разделяй и властвуй"
## Типичные применения стратегии «разделяй и властвуй»
С одной стороны, стратегию "разделяй и властвуй" можно использовать для решения многих классических алгоритмических задач.
С одной стороны, стратегию «разделяй и властвуй» можно использовать для решения многих классических алгоритмических задач.
- **Поиск ближайшей пары точек**: сначала множество точек делится на две части, затем ищется ближайшая пара в каждой части, а затем ближайшая пара, пересекающая границу между двумя частями.
- **Умножение больших чисел**: например, алгоритм Карацубы, который раскладывает умножение больших чисел на несколько умножений и сложений меньших чисел.
- **Умножение матриц**: например, алгоритм Штрассена, который раскладывает умножение больших матриц на несколько умножений и сложений матриц меньшего размера.
- **Задача о Ханойской башне**: задача о Ханойской башне решается рекурсивно и является типичным примером применения стратегии "разделяй и властвуй".
- **Подсчет инверсий**: если в последовательности предыдущее число больше следующего, то такая пара образует инверсию. Эту задачу можно решить с помощью идей "разделяй и властвуй", опираясь на сортировку слиянием.
- **Задача о Ханойской башне**: задача о Ханойской башне решается рекурсивно и является типичным примером применения стратегии «разделяй и властвуй».
- **Подсчет инверсий**: если в последовательности предыдущее число больше следующего, то такая пара образует инверсию. Эту задачу можно решить с помощью идей «разделяй и властвуй», опираясь на сортировку слиянием.
С другой стороны, стратегия "разделяй и властвуй" очень широко применяется при проектировании алгоритмов и структур данных.
С другой стороны, стратегия «разделяй и властвуй» очень широко применяется при проектировании алгоритмов и структур данных.
- **Двоичный поиск**: двоичный поиск делит отсортированный массив на две части по индексу середины, а затем, в зависимости от результата сравнения целевого значения со средним элементом, исключает одну из половин и повторяет ту же операцию на оставшемся интервале.
- **Сортировка слиянием**: она уже была рассмотрена в начале этого раздела, поэтому не будем повторяться.
- **Быстрая сортировка**: в ней выбирается опорное значение, после чего массив делится на два подмассива: один содержит элементы меньше опорного, а другой - больше. Затем такая же операция повторяется для обеих частей, пока в подмассиве не останется один элемент.
- **Блочная сортировка**: ее основная идея заключается в распределении данных по нескольким блокам, сортировке элементов внутри каждого блока и последующем последовательном извлечении элементов из блоков для построения отсортированного массива.
- **Деревья**: например, двоичные деревья поиска, AVL-деревья, красно-черные деревья, B-деревья, B+ деревья и т.д. Их операции поиска, вставки и удаления можно рассматривать как применение стратегии "разделяй и властвуй".
- **Кучи**: куча является особым видом полного двоичного дерева, а такие операции, как вставка, удаление и упорядочивание, по сути содержат идеи "разделяй и властвуй".
- **Хеш-таблицы**: хотя хеш-таблицы напрямую не используют стратегию "разделяй и властвуй", некоторые способы разрешения коллизий косвенно опираются на эту идею. Например, длинные цепочки в методе цепочек могут преобразовываться в красно-черные деревья для повышения эффективности поиска.
- **Деревья**: например, двоичные деревья поиска, AVL-деревья, красно-черные деревья, B-деревья, B+ деревья и т.д. Их операции поиска, вставки и удаления можно рассматривать как применение стратегии «разделяй и властвуй».
- **Кучи**: куча является особым видом полного двоичного дерева, а такие операции, как вставка, удаление и упорядочивание, по сути содержат идеи «разделяй и властвуй».
- **Хеш-таблицы**: хотя хеш-таблицы напрямую не используют стратегию «разделяй и властвуй», некоторые способы разрешения коллизий косвенно опираются на эту идею. Например, длинные цепочки в методе цепочек могут преобразовываться в красно-черные деревья для повышения эффективности поиска.
Нетрудно заметить, что **"разделяй и властвуй" - это "тихая" алгоритмическая идея**, скрыто присутствующая внутри самых разных алгоритмов и структур данных.
Нетрудно заметить, что **«разделяй и властвуй» - это «тихая» алгоритмическая идея**, скрыто присутствующая внутри самых разных алгоритмов и структур данных.
@@ -5,7 +5,7 @@
!!! question
Даны три стержня, обозначенные как `A` , `B` и `C` . В начальном состоянии на стержне `A` находятся $n$ дисков, расположенных сверху вниз в порядке от меньшего к большему. Нужно переместить эти $n$ дисков на стержень `C` , сохранив их исходный порядок (как показано на рисунке ниже). Во время перемещения дисков необходимо соблюдать следующие правила.
1. Диск можно снять только с вершины одного стержня и положить только на вершину другого стержня.
2. За один раз можно перемещать только один диск.
3. Меньший диск всегда должен лежать на большем.
@@ -48,7 +48,7 @@
Для задачи $f(3)$ , то есть когда имеется три диска, ситуация становится сложнее.
Поскольку решения $f(1)$ и $f(2)$ уже известны, можно подойти к задаче с точки зрения стратегии "разделяй и властвуй" и **рассматривать два верхних диска на `A` как единое целое**, выполняя шаги, показанные на рисунке ниже. Так три диска успешно перемещаются с `A` на `C` .
Поскольку решения $f(1)$ и $f(2)$ уже известны, можно подойти к задаче с точки зрения стратегии «разделяй и властвуй» и **рассматривать два верхних диска на `A` как единое целое**, выполняя шаги, показанные на рисунке ниже. Так три диска успешно перемещаются с `A` на `C` .
1. Сделать `B` целевым стержнем, а `C` буферным, и переместить два диска с `A` на `B` .
2. Переместить оставшийся один диск с `A` напрямую на `C` .
@@ -68,7 +68,7 @@
Иначе говоря, **мы разбиваем задачу $f(3)$ на две подзадачи $f(2)$ и одну подзадачу $f(1)$** . Если последовательно решить эти три подзадачи, исходная задача тоже будет решена. Это показывает, что подзадачи независимы и что их решения можно объединить.
Таким образом, можно сформулировать показанную на рисунке ниже стратегию "разделяй и властвуй" для задачи о Ханойской башне: исходная задача $f(n)$ разбивается на две подзадачи $f(n-1)$ и одну подзадачу $f(1)$ , которые затем решаются в следующем порядке.
Таким образом, можно сформулировать показанную на рисунке ниже стратегию «разделяй и властвуй» для задачи о Ханойской башне: исходная задача $f(n)$ разбивается на две подзадачи $f(n-1)$ и одну подзадачу $f(1)$ , которые затем решаются в следующем порядке.
1. Переместить $n-1$ дисков с `A` на `B` с помощью `C` .
2. Переместить оставшийся $1$ диск напрямую с `A` на `C` .
@@ -86,7 +86,7 @@
[file]{hanota}-[class]{}-[func]{solve_hanota}
```
Как показано на рисунке ниже, задача о Ханойской башне формирует дерево рекурсии высоты $n$ , в котором каждый узел представляет подзадачу и соответствует одному открытому вызову `dfs()` ; **поэтому временная сложность равна $O(2^n)$ , а пространственная сложность равна $O(n)$** .
Как показано на рисунке ниже, задача о Ханойской башне формирует дерево рекурсии высоты $n$ , в котором каждый узел представляет подзадачу и соответствует одному открытому вызову `dfs()`. **Поэтому временная сложность равна $O(2^n)$ , а пространственная сложность равна $O(n)$** .
![Дерево рекурсии задачи о Ханойской башне](hanota_problem.assets/hanota_recursive_tree.png)
+2 -2
View File
@@ -5,5 +5,5 @@
!!! abstract
Сложная задача раскладывается слой за слоем, и каждое новое разбиение делает ее проще.
Принцип "разделяй и властвуй" показывает важный факт: если начать с простого, многое перестает быть сложным.
Принцип «разделяй и властвуй» показывает важный факт: если начать с простого, многое перестает быть сложным.
@@ -2,12 +2,12 @@
### Ключевые выводы
- "Разделяй и властвуй" - это распространенная стратегия проектирования алгоритмов, которая включает два этапа: разделение (декомпозицию) и объединение (синтез), и обычно реализуется с помощью рекурсии.
- «Разделяй и властвуй» - это распространенная стратегия проектирования алгоритмов, которая включает два этапа: разделение (декомпозицию) и объединение (синтез), и обычно реализуется с помощью рекурсии.
- Критерии применимости этой стратегии к задаче включают: возможность разложения задачи, независимость подзадач и возможность объединения их решений.
- Сортировка слиянием является типичным применением стратегии "разделяй и властвуй": она рекурсивно делит массив на два равных по длине подмассива, пока не останется массив из одного элемента, после чего начинает поэтапное объединение.
- Использование стратегии "разделяй и властвуй" часто позволяет повысить эффективность алгоритма. С одной стороны, она уменьшает число операций; с другой - после разбиения способствует параллельной оптимизации на уровне системы.
- "Разделяй и властвуй" не только помогает решать многие алгоритмические задачи, но и широко используется при проектировании структур данных и алгоритмов, поэтому его можно встретить буквально повсюду.
- По сравнению с полным перебором адаптивный поиск работает эффективнее. Алгоритмы поиска со сложностью $O(\log n)$ обычно реализуются на основе стратегии "разделяй и властвуй".
- Двоичный поиск - еще одно типичное применение стратегии "разделяй и властвуй", в котором отсутствует шаг объединения решений подзадач. Его можно реализовать рекурсивно, опираясь на эту стратегию.
- Сортировка слиянием является типичным применением стратегии «разделяй и властвуй»: она рекурсивно делит массив на два равных по длине подмассива, пока не останется массив из одного элемента, после чего начинает поэтапное объединение.
- Использование стратегии «разделяй и властвуй» часто позволяет повысить эффективность алгоритма. С одной стороны, она уменьшает число операций. С другой - после разбиения способствует параллельной оптимизации на уровне системы.
- «Разделяй и властвуй» не только помогает решать многие алгоритмические задачи, но и широко используется при проектировании структур данных и алгоритмов, поэтому его можно встретить буквально повсюду.
- По сравнению с полным перебором адаптивный поиск работает эффективнее. Алгоритмы поиска со сложностью $O(\log n)$ обычно реализуются на основе стратегии «разделяй и властвуй».
- Двоичный поиск - еще одно типичное применение стратегии «разделяй и властвуй», в котором отсутствует шаг объединения решений подзадач. Его можно реализовать рекурсивно, опираясь на эту стратегию.
- В задаче построения двоичного дерева исходная задача построения дерева может быть разбита на две подзадачи: построение левого и правого поддеревьев, а реализуется это через разбиение индексных интервалов прямого и симметричного обходов.
- В задаче о Ханойской башне задача размера $n$ разбивается на две подзадачи размера $n-1$ и одну подзадачу размера $1$ . После последовательного решения этих трех подзадач исходная задача также оказывается решенной.