mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-27 02:27:12 +00:00
build
This commit is contained in:
@@ -4,7 +4,7 @@ comments: true
|
||||
|
||||
# 10.1 Двоичный поиск
|
||||
|
||||
<u>Двоичный поиск (binary search)</u> - это эффективный алгоритм поиска, основанный на стратегии "разделяй и властвуй". Он использует упорядоченность данных и на каждом шаге сокращает область поиска вдвое, пока не найдет целевой элемент или пока интервал поиска не опустеет.
|
||||
<u>Двоичный поиск (binary search)</u> - это эффективный алгоритм поиска, основанный на стратегии "разделяй и властвуй". Он использует упорядоченность данных, сокращая на каждом шаге область поиска вдвое, пока не будет найден целевой элемент или пока интервал поиска не опустеет.
|
||||
|
||||
!!! question
|
||||
|
||||
@@ -373,7 +373,7 @@ comments: true
|
||||
|
||||
## 10.1.1 Методы представления интервалов
|
||||
|
||||
Помимо описанного выше двойного замкнутого интервала, часто используется и интервал "слева закрыт, справа открыт", который задается как $[0, n)$ , то есть левая граница включается, а правая - нет. В этом представлении интервал $[i, j)$ пуст, когда $i = j$ .
|
||||
Помимо описанного выше двойного замкнутого интервала, часто используется и левозамкнутый правооткрытый интервал, который задается как $[0, n)$ , то есть левая граница включается, а правая - нет. В этом представлении интервал $[i, j)$ пуст, когда $i = j$ .
|
||||
|
||||
На основе этого представления можно реализовать двоичный поиск с той же функциональностью:
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ comments: true
|
||||
|
||||
Дан упорядоченный массив `nums` длины $n$, который может содержать повторяющиеся элементы. Верните индекс самого левого элемента `target` в массиве. Если массив не содержит этот элемент, верните $-1$ .
|
||||
|
||||
Вспомним метод поиска точки вставки при двоичном поиске: после завершения поиска указатель $i$ указывает на самый левый `target` , **поэтому поиск точки вставки по сути и есть поиск индекса самого левого `target`**.
|
||||
Вспомним метод поиска точки вставки при двоичном поиске: после завершения поиска указатель $i$ указывает на самый левый `target` , **поэтому поиск точки вставки по сути является поиском индекса самого левого `target`**.
|
||||
|
||||
Рассмотрим реализацию поиска левой границы через функцию поиска точки вставки. Обратите внимание: массив может не содержать `target` , и тогда возможны две ситуации.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
comments: true
|
||||
---
|
||||
|
||||
# 10.2 Точка вставки при двоичном поиске
|
||||
# 10.2 Двоичный поиск точки вставки
|
||||
|
||||
Двоичный поиск можно использовать не только для поиска целевого элемента, но и для решения многих вариаций задачи, например для поиска позиции вставки целевого элемента.
|
||||
|
||||
@@ -24,7 +24,7 @@ comments: true
|
||||
|
||||
**Вопрос 2**: если массив не содержит `target` , индекс какого элемента будет точкой вставки?
|
||||
|
||||
Рассмотрим процесс двоичного поиска подробнее: когда `nums[m] < target` , указатель $i$ сдвигается, а значит, приближается к элементу, который больше либо равен `target` . Аналогично указатель $j$ все время приближается к элементу, который меньше либо равен `target` .
|
||||
Рассмотрим процесс двоичного поиска подробнее: когда `nums[m] < target` , указатель $i$ сдвигается вправо и тем самым приближается к элементу, который больше либо равен `target` . Аналогично указатель $j$ постепенно приближается к элементу, который меньше либо равен `target` .
|
||||
|
||||
Следовательно, после завершения двоичного поиска обязательно выполняется следующее: указатель $i$ указывает на первый элемент, больший `target` , а указатель $j$ указывает на первый элемент, меньший `target` . **Нетрудно сделать вывод, что если массив не содержит `target` , то индекс вставки равен $i$** . Код приведен ниже:
|
||||
|
||||
@@ -372,7 +372,7 @@ comments: true
|
||||
|
||||
<p align="center"> Рисунок 10-6 Шаги поиска точки вставки для повторяющихся элементов </p>
|
||||
|
||||
Если посмотреть на следующий код, то видно, что операции в ветвях `nums[m] > target` и `nums[m] == target` совпадают, поэтому эти две ветви можно объединить.
|
||||
Если посмотреть на следующий код, то видно, что действия в ветвях `nums[m] > target` и `nums[m] == target` совпадают, поэтому эти две ветви можно объединить.
|
||||
|
||||
Даже в этом случае можно оставить условия развернутыми, потому что так логика выглядит более ясной и код легче читать.
|
||||
|
||||
@@ -669,6 +669,6 @@ comments: true
|
||||
|
||||
Код в этом разделе записан в стиле "двойного замкнутого интервала". При желании можно самостоятельно реализовать вариант "слева закрыт, справа открыт".
|
||||
|
||||
Если смотреть в целом, суть двоичного поиска сводится к тому, что для указателей $i$ и $j$ заранее задаются цели поиска; целью может быть конкретный элемент (например, `target` ), а может быть и диапазон элементов (например, элементы, меньшие `target` ).
|
||||
Если смотреть в целом, суть двоичного поиска сводится к тому, что для указателей $i$ и $j$ заранее задаются ориентиры поиска; целью может быть конкретный элемент, например `target` , а может быть и диапазон элементов, например все элементы, меньшие `target` .
|
||||
|
||||
В ходе непрерывного двоичного деления указатели $i$ и $j$ постепенно приближаются к заранее заданной цели. В конце они либо успешно находят ответ, либо останавливаются после выхода за границы.
|
||||
|
||||
@@ -9,15 +9,15 @@ icon: material/text-search
|
||||
|
||||
!!! abstract
|
||||
|
||||
Поиск - это приключение в неизвестность: иногда приходится пройти каждый уголок загадочного пространства, а иногда удается быстро зафиксировать цель.
|
||||
Поиск - это движение в неизвестность: иногда приходится пройти каждый уголок пространства, а иногда удается быстро найти цель.
|
||||
|
||||
В этом путешествии каждый новый шаг может привести к ответу, которого мы не ожидали.
|
||||
В этом пути каждый новый шаг может привести к ответу, которого мы не ожидали.
|
||||
|
||||
## Содержание главы
|
||||
|
||||
- [10.1 Двоичный поиск](binary_search.md)
|
||||
- [10.2 Точка вставки двоичного поиска](binary_search_insertion.md)
|
||||
- [10.3 Граничные случаи двоичного поиска](binary_search_edge.md)
|
||||
- [10.4 Стратегия оптимизации через хеширование](replace_linear_by_hashing.md)
|
||||
- [10.5 Алгоритмы поиска: новый взгляд](searching_algorithm_revisited.md)
|
||||
- [10.2 Двоичный поиск точки вставки](binary_search_insertion.md)
|
||||
- [10.3 Двоичный поиск границ](binary_search_edge.md)
|
||||
- [10.4 Стратегии оптимизации хеширования](replace_linear_by_hashing.md)
|
||||
- [10.5 Переосмысление алгоритмов поиска](searching_algorithm_revisited.md)
|
||||
- [10.6 Резюме](summary.md)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
comments: true
|
||||
---
|
||||
|
||||
# 10.4 Стратегии хеш-оптимизации
|
||||
# 10.4 Стратегии оптимизации хеширования
|
||||
|
||||
В алгоритмических задачах **мы часто заменяем линейный поиск на хеш-поиск, чтобы уменьшить временную сложность алгоритма**. Разберем одну задачу, чтобы лучше понять этот прием.
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@ comments: true
|
||||
- **Поиск целевого элемента путем обхода структуры данных**, например обход массива, списка, дерева или графа.
|
||||
- **Эффективный поиск элементов с использованием структуры организации данных или априорной информации**, например двоичный поиск, хеш-поиск и поиск в двоичном дереве поиска.
|
||||
|
||||
Нетрудно заметить, что эти темы уже рассматривались в предыдущих главах, поэтому алгоритмы поиска нам уже знакомы. В этом разделе мы еще раз посмотрим на них, но уже более системно.
|
||||
Нетрудно заметить, что эти темы уже рассматривались в предыдущих главах, поэтому алгоритмы поиска нам уже знакомы. В этом разделе мы систематизируем полученные ранее знания и еще раз посмотрим на них как на единую группу методов.
|
||||
|
||||
## 10.5.1 Полный перебор
|
||||
|
||||
Полный перебор заключается в том, что мы обходим каждый элемент структуры данных, чтобы найти целевой элемент.
|
||||
|
||||
- "Линейный поиск" применяется к линейным структурам данных, таким как массивы и списки. Он начинается с одного конца структуры данных и последовательно проверяет элементы, пока не найдет целевой элемент или пока не достигнет другого конца структуры данных.
|
||||
- "Поиск в ширину" и "поиск в глубину" - это две стратегии обхода графов и деревьев. Поиск в ширину стартует из начального узла и исследует все узлы текущего уровня, прежде чем переходить к следующему. Поиск в глубину стартует из начального узла, проходит один путь до конца, затем возвращается назад и пробует другие пути, пока не будет полностью пройдена вся структура данных.
|
||||
- "Обход в ширину" и "обход в глубину" - это две стратегии обхода графов и деревьев. Обход в ширину стартует из начального узла и исследует все узлы текущего уровня, прежде чем переходить к следующему. Обход в глубину стартует из начального узла, проходит один путь до конца, затем возвращается назад и пробует другие пути, пока не будет полностью пройдена вся структура данных.
|
||||
|
||||
Преимущество полного перебора состоит в его простоте и универсальности, **поскольку он не требует предварительной обработки данных и использования дополнительных структур данных**.
|
||||
|
||||
@@ -32,13 +32,13 @@ comments: true
|
||||
- "Хеш-поиск" использует хеш-таблицу для построения отображения между поисковыми данными и целевыми данными, благодаря чему запросы выполняются эффективно.
|
||||
- "Поиск в дереве" ведется в конкретной древовидной структуре (например, в двоичном дереве поиска) и позволяет быстро отсекать узлы на основе сравнения значений, чтобы найти цель.
|
||||
|
||||
Преимущество этих алгоритмов в высокой эффективности, **их временная сложность может достигать $O(\log n)$ и даже $O(1)$** .
|
||||
Преимущество этих алгоритмов заключается в высокой эффективности: **их временная сложность может достигать $O(\log n)$ и даже $O(1)$** .
|
||||
|
||||
Однако **для использования таких алгоритмов обычно требуется предварительная обработка данных**. Например, для двоичного поиска нужно заранее отсортировать массив, а хеш-поиск и поиск в дереве требуют дополнительных структур данных, поддержание которых тоже отнимает время и память.
|
||||
|
||||
!!! tip
|
||||
|
||||
Адаптивные алгоритмы поиска часто называют алгоритмами поиска в узком смысле, **поскольку они в основном предназначены для быстрого поиска целевого элемента в конкретной структуре данных**.
|
||||
Адаптивные алгоритмы поиска часто называют алгоритмами поиска в узком смысле, **поскольку они в основном предназначены для быстрого нахождения целевого элемента в конкретной структуре данных**.
|
||||
|
||||
## 10.5.3 Выбор метода поиска
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ comments: true
|
||||
### 1. Ключевые выводы
|
||||
|
||||
- Двоичный поиск опирается на упорядоченность данных и выполняет поиск путем циклического сокращения интервала вдвое. Он требует упорядоченных входных данных и подходит только для массивов или структур данных, реализованных на их основе.
|
||||
- Полный перебор находит данные путем обхода структуры данных. Линейный поиск подходит для массивов и списков, а поиск в ширину и поиск в глубину подходят для графов и деревьев. Эти алгоритмы универсальны и не требуют предварительной обработки данных, но их временная сложность $O(n)$ сравнительно велика.
|
||||
- Полный перебор находит данные путем обхода структуры данных. Линейный поиск подходит для массивов и списков, а обход в ширину и обход в глубину подходят для графов и деревьев. Эти алгоритмы универсальны и не требуют предварительной обработки данных, но их временная сложность $O(n)$ сравнительно велика.
|
||||
- Хеш-поиск, поиск в дереве и двоичный поиск относятся к эффективным методам поиска и позволяют быстро находить целевой элемент в конкретных структурах данных. Такие алгоритмы обладают высокой эффективностью, их временная сложность может достигать $O(\log n)$ и даже $O(1)$ , но обычно им нужны дополнительные структуры данных.
|
||||
- На практике нужно анализировать размер данных, требования к производительности поиска, а также частоту запросов и обновлений данных, чтобы выбрать подходящий метод поиска.
|
||||
- Линейный поиск подходит для небольших или часто обновляемых наборов данных; двоичный поиск - для больших отсортированных данных; хеш-поиск - для сценариев с высокими требованиями к скорости запросов и без необходимости поиска по диапазону; поиск в дереве - для больших динамических данных, где нужно поддерживать порядок и выполнять диапазонные запросы.
|
||||
|
||||
Reference in New Issue
Block a user