mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-09 14:06:06 +00:00
deploy
This commit is contained in:
@@ -65,8 +65,8 @@
|
||||
|
||||
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
|
||||
<style>:root{--md-text-font:"Noto Sans";--md-code-font:"JetBrains Mono"}</style>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=PT+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
|
||||
<style>:root{--md-text-font:"PT Sans";--md-code-font:"JetBrains Mono"}</style>
|
||||
|
||||
|
||||
|
||||
@@ -574,7 +574,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
Глава 1. Знакомство с алгоритмами
|
||||
Глава 1. Введение в алгоритмы
|
||||
|
||||
|
||||
|
||||
@@ -596,7 +596,7 @@
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
|
||||
|
||||
Глава 1. Знакомство с алгоритмами
|
||||
Глава 1. Введение в алгоритмы
|
||||
|
||||
|
||||
</label>
|
||||
@@ -646,7 +646,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
1.2 Что такое структуры данных и алгоритмы
|
||||
1.2 Что такое алгоритм
|
||||
|
||||
|
||||
|
||||
@@ -1181,7 +1181,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
Глава 4. Массив и связный список
|
||||
Глава 4. Массивы и списки
|
||||
|
||||
|
||||
|
||||
@@ -1203,7 +1203,7 @@
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
|
||||
|
||||
Глава 4. Массив и связный список
|
||||
Глава 4. Массивы и списки
|
||||
|
||||
|
||||
</label>
|
||||
@@ -1309,7 +1309,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
4.4 Память и кеш *
|
||||
4.4 Оперативная память и кэш *
|
||||
|
||||
|
||||
|
||||
@@ -1591,7 +1591,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
Глава 6. Хеширование
|
||||
Глава 6. Хеш-таблицы
|
||||
|
||||
|
||||
|
||||
@@ -1613,7 +1613,7 @@
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
|
||||
|
||||
Глава 6. Хеширование
|
||||
Глава 6. Хеш-таблицы
|
||||
|
||||
|
||||
</label>
|
||||
@@ -1691,7 +1691,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
6.3 Хеш-алгоритмы
|
||||
6.3 Алгоритмы хеширования
|
||||
|
||||
|
||||
|
||||
@@ -1786,7 +1786,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
Глава 7. Дерево
|
||||
Глава 7. Деревья
|
||||
|
||||
|
||||
|
||||
@@ -1808,7 +1808,7 @@
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
|
||||
|
||||
Глава 7. Дерево
|
||||
Глава 7. Деревья
|
||||
|
||||
|
||||
</label>
|
||||
@@ -1886,7 +1886,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
7.3 Представление дерева массивом
|
||||
7.3 Представление двоичного дерева массивом
|
||||
|
||||
|
||||
|
||||
@@ -1970,7 +1970,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
7.6 Резюме
|
||||
7.6 Краткие итоги
|
||||
|
||||
|
||||
|
||||
@@ -2133,7 +2133,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
8.3 Задача Top-K
|
||||
8.3 Задача Top-k
|
||||
|
||||
|
||||
|
||||
@@ -2224,7 +2224,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
Глава 9. Граф
|
||||
Глава 9. Графы
|
||||
|
||||
|
||||
|
||||
@@ -2246,7 +2246,7 @@
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
|
||||
|
||||
Глава 9. Граф
|
||||
Глава 9. Графы
|
||||
|
||||
|
||||
</label>
|
||||
@@ -2296,7 +2296,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
9.2 Базовые операции над графами
|
||||
9.2 Базовые операции графа
|
||||
|
||||
|
||||
|
||||
@@ -2352,7 +2352,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
9.4 Резюме
|
||||
9.4 Краткие итоги
|
||||
|
||||
|
||||
|
||||
@@ -2491,7 +2491,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
10.2 Точка вставки двоичного поиска
|
||||
10.2 Двоичный поиск точки вставки
|
||||
|
||||
|
||||
|
||||
@@ -2519,7 +2519,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
10.3 Граничные случаи двоичного поиска
|
||||
10.3 Двоичный поиск границ
|
||||
|
||||
|
||||
|
||||
@@ -2547,7 +2547,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
10.4 Стратегия оптимизации через хеширование
|
||||
10.4 Стратегии оптимизации хеширования
|
||||
|
||||
|
||||
|
||||
@@ -2575,7 +2575,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
10.5 Алгоритмы поиска: новый взгляд
|
||||
10.5 Переосмысление алгоритмов поиска
|
||||
|
||||
|
||||
|
||||
@@ -2780,7 +2780,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
11.3 Пузырьковая сортировка
|
||||
11.3 Сортировка пузырьком
|
||||
|
||||
|
||||
|
||||
@@ -2808,7 +2808,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
11.4 Сортировка вставкой
|
||||
11.4 Сортировка вставками
|
||||
|
||||
|
||||
|
||||
@@ -3113,7 +3113,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
12.1 Алгоритмы разделяй и властвуй
|
||||
12.1 Стратегия разделяй и властвуй
|
||||
|
||||
|
||||
|
||||
@@ -3141,7 +3141,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
12.2 Стратегия поиска разделяй и властвуй
|
||||
12.2 Поисковая стратегия разделяй и властвуй
|
||||
|
||||
|
||||
|
||||
@@ -3418,7 +3418,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
13.4 Задача о $n$ ферзях
|
||||
13.4 Задача о n ферзях
|
||||
|
||||
|
||||
|
||||
@@ -3561,7 +3561,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
14.1 Введение в динамическое программирование
|
||||
14.1 Первое знакомство с динамическим программированием
|
||||
|
||||
|
||||
|
||||
@@ -3713,7 +3713,7 @@
|
||||
<a href="#2-2" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
2. Метод 2: поиск с мемоизацией
|
||||
2. Метод 2: мемоизация
|
||||
|
||||
</span>
|
||||
</a>
|
||||
@@ -3765,7 +3765,7 @@
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
14.5 Задача о неограниченном рюкзаке
|
||||
14.5 Задача о полном рюкзаке
|
||||
|
||||
|
||||
|
||||
@@ -4332,7 +4332,7 @@
|
||||
<a href="#2-2" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
2. Метод 2: поиск с мемоизацией
|
||||
2. Метод 2: мемоизация
|
||||
|
||||
</span>
|
||||
</a>
|
||||
@@ -4399,7 +4399,7 @@
|
||||
|
||||
<!-- Page content -->
|
||||
<h1 id="144-0-1">14.4 Задача о рюкзаке 0-1<a class="headerlink" href="#144-0-1" title="Permanent link">¶</a></h1>
|
||||
<p>Задача о рюкзаке - это очень хороший вводный пример для динамического программирования и одна из самых типичных форм задач этого класса. У нее существует множество вариантов, например задача о рюкзаке 0-1, задача о полном рюкзаке, задача о многократном рюкзаке и т.д.</p>
|
||||
<p>Задача о рюкзаке является отличным примером для начала изучения динамического программирования и представляет собой одну из наиболее распространенных форм этой задачи. У нее существует множество вариантов, например задача о рюкзаке 0-1, задача о полном рюкзаке, задача о многократном рюкзаке и т.д.</p>
|
||||
<p>В этом разделе сначала разберем самый распространенный вариант - задачу о рюкзаке 0-1.</p>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">Question</p>
|
||||
@@ -4409,8 +4409,8 @@
|
||||
<p><img alt="Пример данных для задачи о рюкзаке 0-1" class="animation-figure" src="../knapsack_problem.assets/knapsack_example.png" /></p>
|
||||
<p align="center"> Рисунок 14-17 Пример данных для задачи о рюкзаке 0-1 </p>
|
||||
|
||||
<p>На задачу о рюкзаке 0-1 можно смотреть как на процесс из <span class="arithmatex">\(n\)</span> раундов решений: для каждого предмета есть два решения - не класть его в рюкзак или положить в рюкзак. Поэтому задача удовлетворяет модели дерева решений.</p>
|
||||
<p>Цель задачи - найти "максимальную суммарную стоимость при ограниченной вместимости рюкзака", значит, с большой вероятностью это задача динамического программирования.</p>
|
||||
<p>Задачу о рюкзаке 0-1 можно рассматривать как процесс из <span class="arithmatex">\(n\)</span> раундов принятия решений: для каждого предмета есть два решения - не класть его в рюкзак или положить в рюкзак. Поэтому задача удовлетворяет модели дерева решений.</p>
|
||||
<p>Цель задачи - найти "максимальную суммарную стоимость при ограниченной вместимости рюкзака", а это с большой вероятностью указывает на задачу динамического программирования.</p>
|
||||
<p><strong>Шаг 1: продумать решения на каждом раунде, определить состояние и тем самым получить таблицу <span class="arithmatex">\(dp\)</span></strong></p>
|
||||
<p>Для каждого предмета возможны два случая: не класть его в рюкзак, тогда вместимость не меняется; или положить его в рюкзак, тогда оставшаяся вместимость уменьшается. Отсюда получается определение состояния: текущий номер предмета <span class="arithmatex">\(i\)</span> и текущая вместимость рюкзака <span class="arithmatex">\(c\)</span> , то есть состояние обозначается как <span class="arithmatex">\([i, c]\)</span> .</p>
|
||||
<p>Подзадача, соответствующая состоянию <span class="arithmatex">\([i, c]\)</span> , такова: <strong>максимальная стоимость, которую можно получить, используя первые <span class="arithmatex">\(i\)</span> предметов и рюкзак вместимости <span class="arithmatex">\(c\)</span></strong>. Ее решение обозначается через <span class="arithmatex">\(dp[i, c]\)</span> .</p>
|
||||
@@ -4702,7 +4702,7 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])
|
||||
<p><img alt="Дерево полного перебора для задачи о рюкзаке 0-1" class="animation-figure" src="../knapsack_problem.assets/knapsack_dfs.png" /></p>
|
||||
<p align="center"> Рисунок 14-18 Дерево полного перебора для задачи о рюкзаке 0-1 </p>
|
||||
|
||||
<h3 id="2-2">2. Метод 2: поиск с мемоизацией<a class="headerlink" href="#2-2" title="Permanent link">¶</a></h3>
|
||||
<h3 id="2-2">2. Метод 2: мемоизация<a class="headerlink" href="#2-2" title="Permanent link">¶</a></h3>
|
||||
<p>Чтобы каждая перекрывающаяся подзадача вычислялась только один раз, используем таблицу памяти <code>mem</code> для хранения решений подзадач, где <code>mem[i][c]</code> соответствует <span class="arithmatex">\(dp[i, c]\)</span> .</p>
|
||||
<p>После введения мемоизации <strong>временная сложность определяется числом подзадач</strong> , то есть равна <span class="arithmatex">\(O(n \times cap)\)</span> . Код выглядит так:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="2:13"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><input id="__tabbed_2_4" name="__tabbed_2" type="radio" /><input id="__tabbed_2_5" name="__tabbed_2" type="radio" /><input id="__tabbed_2_6" name="__tabbed_2" type="radio" /><input id="__tabbed_2_7" name="__tabbed_2" type="radio" /><input id="__tabbed_2_8" name="__tabbed_2" type="radio" /><input id="__tabbed_2_9" name="__tabbed_2" type="radio" /><input id="__tabbed_2_10" name="__tabbed_2" type="radio" /><input id="__tabbed_2_11" name="__tabbed_2" type="radio" /><input id="__tabbed_2_12" name="__tabbed_2" type="radio" /><input id="__tabbed_2_13" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">Python</label><label for="__tabbed_2_2">C++</label><label for="__tabbed_2_3">Java</label><label for="__tabbed_2_4">C#</label><label for="__tabbed_2_5">Go</label><label for="__tabbed_2_6">Swift</label><label for="__tabbed_2_7">JS</label><label for="__tabbed_2_8">TS</label><label for="__tabbed_2_9">Dart</label><label for="__tabbed_2_10">Rust</label><label for="__tabbed_2_11">C</label><label for="__tabbed_2_12">Kotlin</label><label for="__tabbed_2_13">Ruby</label></div>
|
||||
@@ -5412,13 +5412,13 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])
|
||||
<p align="center"> Рисунок 14-20 Процесс динамического программирования для задачи о рюкзаке 0-1 </p>
|
||||
|
||||
<h3 id="4">4. Оптимизация пространства<a class="headerlink" href="#4" title="Permanent link">¶</a></h3>
|
||||
<p>Поскольку каждое состояние зависит только от состояния в предыдущей строке, можно использовать два массива, которые будут "перекатываться" вперед, и тем самым уменьшить пространственную сложность с <span class="arithmatex">\(O(n^2)\)</span> до <span class="arithmatex">\(O(n)\)</span> .</p>
|
||||
<p>Поскольку каждое состояние зависит только от состояния в предыдущей строке, можно использовать два массива, которые будут продвигаться вперед по очереди, и тем самым уменьшить пространственную сложность с <span class="arithmatex">\(O(n^2)\)</span> до <span class="arithmatex">\(O(n)\)</span> .</p>
|
||||
<p>Если пойти дальше, можно спросить: можно ли оптимизировать память так, чтобы использовать только один массив? Наблюдение показывает, что каждое состояние зависит от клетки прямо сверху и клетки слева сверху. Предположим, что у нас есть только один массив, и в момент начала обхода строки <span class="arithmatex">\(i\)</span> он еще хранит состояния строки <span class="arithmatex">\(i-1\)</span> .</p>
|
||||
<ul>
|
||||
<li>Если обходить массив слева направо, то к моменту вычисления <span class="arithmatex">\(dp[i, j]\)</span> значения слева сверху <span class="arithmatex">\(dp[i-1, 1]\)</span> ~ <span class="arithmatex">\(dp[i-1, j-1]\)</span> могут уже быть перезаписаны, и правильный результат перехода состояния получить не удастся.</li>
|
||||
<li>Если же обходить массив справа налево, проблема перезаписи не возникает, и переход состояния вычисляется корректно.</li>
|
||||
</ul>
|
||||
<p>На рисунке 14-21 показан процесс перехода от строки <span class="arithmatex">\(i = 1\)</span> к строке <span class="arithmatex">\(i = 2\)</span> при использовании одного массива. Попробуйте сопоставить его с разницей между прямым и обратным обходом.</p>
|
||||
<p>На рисунке 14-21 показан процесс перехода от строки <span class="arithmatex">\(i = 1\)</span> к строке <span class="arithmatex">\(i = 2\)</span> при использовании одного массива. С его помощью удобно понять различие между прямым и обратным обходом.</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="5:6"><input checked="checked" id="__tabbed_5_1" name="__tabbed_5" type="radio" /><input id="__tabbed_5_2" name="__tabbed_5" type="radio" /><input id="__tabbed_5_3" name="__tabbed_5" type="radio" /><input id="__tabbed_5_4" name="__tabbed_5" type="radio" /><input id="__tabbed_5_5" name="__tabbed_5" type="radio" /><input id="__tabbed_5_6" name="__tabbed_5" type="radio" /><div class="tabbed-labels"><label for="__tabbed_5_1"><1></label><label for="__tabbed_5_2"><2></label><label for="__tabbed_5_3"><3></label><label for="__tabbed_5_4"><4></label><label for="__tabbed_5_5"><5></label><label for="__tabbed_5_6"><6></label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -5771,7 +5771,7 @@ aria-label="Нижний колонтитул"
|
||||
<a
|
||||
href="../unbounded_knapsack_problem/"
|
||||
class="md-footer__link md-footer__link--next"
|
||||
aria-label="Вперед: 14.5 Задача о неограниченном рюкзаке"
|
||||
aria-label="Вперед: 14.5 Задача о полном рюкзаке"
|
||||
rel="next"
|
||||
>
|
||||
<div class="md-footer__title">
|
||||
@@ -5779,7 +5779,7 @@ aria-label="Нижний колонтитул"
|
||||
Вперед
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
14.5 Задача о неограниченном рюкзаке
|
||||
14.5 Задача о полном рюкзаке
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer__button md-icon">
|
||||
|
||||
Reference in New Issue
Block a user