Программа курса:
Разбор задачи: Лопание шариков
Предложенный нами код:
def maxCoins(nums):
memo, nums = {}, [1] + [num for num in nums if num] + [1]
def dfs(l, r):
if r - l == 1: return 0
if (l, r) not in memo: memo[(l, r)] = max(nums[l] * nums[i] * nums[r] + dfs(l, i) + dfs(i, r) for i in range(l + 1, r))
return memo[(l, r)]
return dfs(0, len(nums) - 1)В данной реализации используется метод рекурсии с мемоизацией для нахождения максимального количества монет, которые можно собрать, лопая шарики оптимальным образом.
1. Подготовка входных данных
nums = [1] + [num for num in nums if num] + [1]
Эта строка делает следующее:
- Добавляет фиктивные единицы (
1) в начало и конец массиваnums. Эти фиктивные шарики обеспечивают корректные вычисления для крайних шариков, так как на границах массива нас просят считать, что значение шарика равно1. - Исключает нулевые значения из массива, так как шарики с числом
0не влияют на результат.
Пример:
Вход: nums = [3, 1, 5, 8]
После обработки: nums = [1, 3, 1, 5, 8, 1].
2. Рекурсивная функция dfs
Функция dfs(l, r) вычисляет максимальное количество монет, которые можно собрать, лопая шарики на подотрезке nums[l:r].
Идея: на каждом шаге выбираем шарик i для последнего лопания на отрезке l до r.
if r - l == 1:
return 0
- Если отрезок слишком мал (между
lиrнет шариков, т.е.r - l == 1), возвращаем0, так как лопать нечего.
3. Мемоизация
if (l, r) not in memo:
memo[(l, r)] = max(nums[l] * nums[i] * nums[r] + dfs(l, i) + dfs(i, r) for i in range(l + 1, r))
- Проверяется, вычислялся ли уже результат для отрезка
(l, r). Если нет, рекурсивно вычисляем результат. - Для каждого индекса
iна отрезке[l+1, r-1]рассматриваем случай, когда шарикiлопается последним.- При этом:
- Учитывается количество монет за лопание
nums[l] * nums[i] * nums[r]. - Рекурсивно вычисляются монеты для двух оставшихся подотрезков:
[l, i]и[i, r].
- Учитывается количество монет за лопание
- При этом:
4. Возврат результата
return memo[(l, r)]
- После вычисления результат сохраняется в словарь
memoдля предотвращения повторных вычислений.
5. Инициализация вызова
return dfs(0, len(nums) - 1)
- Вызывается функция
dfsдля всего массива (от0доlen(nums) - 1), чтобы найти оптимальное решение для всех шариков.
Пример работы алгоритма
Рассмотрим входные данные nums = [3, 1, 5, 8].
После обработки: nums = [1, 3, 1, 5, 8, 1].
Начальный вызов
dfs(0, 5)- Рассматриваем весь массив
[1, 3, 1, 5, 8, 1]. - Выбираем шарик
iдля лопания последним из индексов1до4.
- Рассматриваем весь массив
- Вычисления для подотрезков Для каждого выбранного
i:- Лопаем шарик
i. - Вызываем
dfsдля левого и правого подотрезков.
- Лопаем шарик
- Пример разбиения
- Для
i = 3(шарик с числом5):- Лопаем
5, получаемnums[2] * nums[3] * nums[4] = 1 * 5 * 8 = 40. - Вычисляем
dfs(0, 3)для левого подотрезка[1, 3, 1, 5]. - Вычисляем
dfs(3, 5)для правого подотрезка[5, 8, 1].
- Лопаем
- Для
- Использование мемоизации
- Если подотрезок уже был обработан, результат берется из
memo, а не вычисляется заново.
- Если подотрезок уже был обработан, результат берется из
Вы должны Войти или Зарегистрироваться чтобы оставлять комментарии