10.5. Демонстрация - Автоответчик
Шаг 1
Подзадачи будут похожи на те, что были в прошлой задаче (это ведь та же самая задача, только решённая не за все дни, а только за дни от первого до каждого дня по очереди). Что будет результатом подзадачи? В каждый день у нас есть два выбора: продавать акцию или держать её. Если мы её продаём, то получаем прибыль как разницу между текущей ценой и встретившейся до текущего дня минимальной ценой. Если мы держим, прибыль будет такой же, как если бы мы продали акцию в прошлый день. Это следует из того, что мы либо уже получили максимальную прибыль с предыдущей продажи, и эта прибыль является максимальной до текущего дня, либо ещё не достигли самого пика и продавать её бессмысленно, так что имеет смысл снова принять это максимальной прибылью. Большее из этих двух чисел и есть решение подзадачи (обновление максимума почти как в прошлой задаче). Давайте теперь напишем наше решение.
import {answer} from './logger';
function countRatio(prices, profit) {
answer(profit, 10, profit / 10)
}
countRatio([4,3,1,4,3,6], 3);
Шаг 2
Как видим из решения, некоторые части заметно перекликаются с предыдущей демонстрацией. Это стандартная ситуация для всех решений при помощи динамического программирования. Сначала мы заводим память для хранения результатов подзадач, а затем решаем их последовательно, в каждой используя решения предыдущих, от которых она зависит..
import {answer} from './logger';
function countRatio(prices, profit) {
const profitByDays = Array(prices.length).fill(0);
// Будем хранить отдельно минимальную цену за все прошедшие дни
let minPrice = prices[0];
for (let i = 1; i < prices.length; i++) {
// Обновляем минимальную цену
minPrice = Math.min(minPrice, prices[i]);
// Если продаём, то получаем прибыль, равную разнице текущей и минимальной цен
const sellProfit = prices[i] - minPrice;
// Если не продаём, значит остаёмся при максимальной прибыли за предыдущие дни
const holdProfit = prices[i - 1];
// А максимальная прибыль получается при принятии лучшего решения
profitByDays[i] = Math.max(sellProfit, holdProfit);
}
const maxProfit = profitByDays[profitByDays.length - 1];
answer(profit, maxProfit, profit / maxProfit)
}
countRatio([4,3,1,4,3,6], 4);
File logger.js
const result = document.getElementById('result');
export function answer(current, perfect, ratio) {
result.innerText = `Ты заработал ${current}$, а мог бы ${perfect}$. Ты на ${Math.round(ratio * 100)}% близок к идеалу!`;
}