Сначала бонусная задача: Максимум скользящего окна. Если вы уже решили ее, вам следует сначала попытаться решить проблему, которую мы сегодня обсуждаем. Если нет, то читаем описание:

Для заданного массива nums имеется скользящее окно размером k, которое перемещается с самого левого края массива на самое правое. Вы можете видеть только k чисел в окне. Каждый раз скользящее окно перемещается вправо на одну позицию. Вернуть максимальное скользящее окно.

Приведенный пример облегчает понимание.

Input: nums = [1,3,-1,-3,5,3,6,7], and k = 3
Output: [3,3,5,5,6,7] 
Explanation: 

Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

Довольно простая проблема. Попробуйте подумать над решением. Я вернусь к этой проблеме позже. Помните, решение грубой силы, которое заключается в переборе массива и для каждой позиции i, поиске максимума подмассива [i, i+k-1], запустив еще один цикл из k, выиграл не работаю здесь из-за ограничений. Временная сложность этого решения составляет O(n*k), где n — длина массива, а k — размер окна. Ограничение: 1 ≤ n ≤ 10⁵, 1 ≤ k ≤ n

Теперь давайте перейдем к реальной проблеме, которую мы здесь должны решить: Сумма подпоследовательностей с ограничениями. Вот описание:

Учитывая целочисленный массив nums и целое число k, вернуть максимальную сумму непустой подпоследовательности этого такой массив, что для каждых двух последовательных целых чисел в подпоследовательности nums[i] и nums[j], где i ‹ j выполняется условие j - i ≤ k.

Проще говоря, если вы взяли число в i-й позиции массива и хотите выбрать другое, вам нужно выбрать из следующих k элементы, находящиеся в диапазоне [i+1, i+k]. Пример:

числа = [10, -2, -10, -5, 20], к = 2

Если бы не было ограничения на k, очевидно, ответ был бы равен 30 (если взять 10 и 20 из позиций 0 и 4). Но 4-0 ≥ 2, так что это не удовлетворяет условию. Максимальная сумма в этом массиве равна 23 (10+(-2)+(-5)+20)

Теперь обсудим решение. На самом деле это довольно простая проблема DP. Нам понадобится только один параметр: pos (это индекс, в котором мы находимся). Здесь есть небольшая загвоздка: мы можем начать брать числа с любой позиции, которую захотим, но как только мы начали, мы должны поддерживать условие или игнорировать все оставшиеся элементы. Итак, мы перебираем массив, и для каждой позиции у нас есть два варианта:

  1. Это первый элемент, который я беру. Так что нет необходимости рассматривать предыдущие элементы.
  2. Это не первый элемент, поэтому должны быть некоторые элементы, которые я выбрал раньше. Поэтому постарайтесь найти максимальную сумму, которую я могу получить из предыдущих элементов.

Вот решение:

for(int i = 0; i < n; i++)
{
    int mx = INT_MIN / 3;
    for(int j = i-1; j >= max(0, i-k); j--)
    {
        mx = max(mx, dp[j]);
    }
    // adding mx means considering previous elements
    dp[i] = max(nums[i], nums[i] + mx);
    ans = max(ans, dp[i]);
}
    dp[i] = max(nums[i], nums[i] + mx);
    ans = max(ans, dp[i]);
}

Мы легко видим, что есть два цикла, поэтому временная сложность составляет O(n*k), что недостаточно эффективно, поскольку 1 ≤ n ≤ 10⁵, 1 ≤ k ≤ n >

Мы не можем избежать внешнего цикла. Поэтому нам нужно как-то устранить внутренний цикл. Можете ли вы узнать эту петлю и что она делает? Да, он находит максимальное значение окна размером k и каждый раз, когда окно сдвигается на одну позицию вправо. Как раз проблема, которую мы обсуждали ранее.

Существует O(n*logk)решение с помощью мультимножества. Это довольно прямолинейно и легко реализовать, и оно пройдет решение. Но мы поговорим о другом методе, который снизит сложность до O(n). Это называется Монотонная очередь.

Вот определение:

Монотонная очередь — это структура данных, в которой элементы от начала до конца строго либо увеличиваются, либо уменьшаются.

Итак, в этой задаче нам понадобится строго убывающая монотонная очередь. Как это будет работать? Приходится как-то вставлять и удалять элементы из монотонной очереди, когда окно скользит так, чтобы оно оставалось строго убывающим. В результате передний элемент всегда должен иметь максимальное значение. Этого можно достичь в два этапа:

  1. Мы вставим наш элемент сзади. Перед вставкой нам нужно удалить все элементы, которые меньше или равны этому элементу, чтобы он оставался строго убывающим.
  2. Прежде чем мы возьмем максимальное значение спереди, нам нужно убедиться, что оно принадлежит окну. Поэтому мы удалим элементы, которые не входят в этот диапазон. (Это может измениться в зависимости от проблемы)

Итак, мы видим, что у нас в основном есть два вида операций. Снятие, вставка сзади и снятие, выглядывание спереди. Deque — лучшая структура данных для реализации этого, потому что все операции, упомянутые выше, могут быть выполнены со сложностью O(1). Для лучшего понимания ниже приведен пошаговый пример:

Window position             Montonic Queue                     Max
---------------             --------------                    -----
[1  3  -1] -3  5  3  6  7   [1] -> [3] (removed 1) -> [3 -1]    3
 1 [3  -1  -3] 5  3  6  7   [3 - 1 -3]                          3
 1  3 [-1  -3  5] 3  6  7   [-1 -3] (removed 3 from front) ->   5
                            [5] (removed all elements <= 5) 
 1  3  -1 [-3  5  3] 6  7   [5 3]                               5
 1  3  -1  -3 [5  3  6] 7   [6] (removed all elements <= 6)     6
 1  3  -1  -3  5 [3  6  7]  [7] (removed all elements <= 7)     7

Вот полное решение (здесь мы сохраняем индексы в двухсторонней очереди, но ограничение остается для элементов с этими индексами):

int ans = INT_MIN;
deque<int> dq;
for(int i = 0; i < n; i++)
{
    int mx = 0;
    while(!dq.empty() && dq.front() < i-k)
        dq.pop_front();
    dp[i] = nums[i] + (dq.empty() ? 0 : dp[dq.front()]);
    while(!dq.empty() && dp[i] >= dp[dq.back()])
        dq.pop_back();
    if(dp[i] > 0)
        dq.push_back(i);
    ans = max(ans, dp[i]);
}

Вот некоторые другие проблемы, которые необходимо решить:

496. Следующий Большой Элемент I

503. Следующий Великий Элемент II

Удачного кодирования! :смайлик: