Предполагая, что есть хотя бы одна пара элементов, удовлетворяющих условиям, и нет умножения двух элементов в ней, переполнения, это может быть сделано во Theta(n-k)времени и Theta(1)пространстве в наихудшем и наилучшем случае, с чем-то вроде этого:
auto back_max = a[0];
auto back_min = a[0];
auto best = a[0]*a[k+1];
for(std::size_t i=1; i<n-(k+1); ++i) {
back_max = std::max(back_max, a[i]);
back_min = std::min(back_min, a[i]);
best = std::min(best, std::min(a[i+k+1]*back_max, a[i+k+1]*back_min));
}
return best;
Это оптимально с точки зрения асимптотической сложности в худшем случае как для времени, так и для пространства, поскольку оптимальным произведением может быть как минимум a[0]любой из n-(k+1)элементов на расстоянии k+1, поэтому n-(k+1)любой алгоритм, решающий проблему, должен быть прочитан как минимум целыми числами.
Идея алгоритма заключается в следующем:
Оптимальный продукт использует два элемента a, предположим, что это a[r]и a[s]. Без ограничения общности можно предположить, что, s > rпоскольку произведение является коммутативным.
Из-за ограничения abs(s-r) > kэто означает, что s >= k+1. Теперь sкаждый из индексов может удовлетворять этому условию, поэтому мы перебираем эти индексы. Это итерация iв показанном коде, но k+1для удобства она сдвинута (не имеет большого значения). Для каждой итерации нам нужно найти оптимальный продукт с i+k+1наибольшим индексом и сравнить его с предыдущим лучшим предположением.
Все возможные индексы, i+k+1с которыми нужно соединиться, являются меньшими или равными iиз-за требования к расстоянию. Нам также нужно было бы повторить все это, но в этом нет необходимости, потому что минимальный a[i+k+1]*a[j]избыточный jпри фиксированном iравен min(a[i+k+1]*max(a[j]), a[i+k+1]*min(a[j]))монотонности продукта (принимая во внимание минимум как по отношению к минимуму, так и максимальный по сравнению a[j]с учетом двух возможных признаки a[i+k+1]или эквивалентно два возможных направления монотонности.)
Так как набор a[j]значений, для которых мы оптимизируем здесь, просто {a[0], ..., a[i]}, который просто увеличивается на один элемент ( a[i]) в каждой итерации i, мы можем просто отслеживать max(a[j])и min(a[j])с отдельными переменными, обновляя их, если они a[i]больше или меньше предыдущих оптимальных значений. Это делается с помощью back_maxи back_minв примере кода.
Первый шаг итерации ( i=0) пропускается в цикле и вместо этого выполняется как инициализация переменных.
std::vector? @Scheff - сортировка разрушила бы исходные «дистанционные» отношения.