Suponiendo que haya al menos un par de elementos que satisfagan las condiciones y que no se desborde la multiplicación de dos elementos, esto puede hacerse en el Theta(n-k)
tiempo y el Theta(1)
espacio en el peor y el mejor de los casos, con algo como esto:
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;
Esto es óptimo en términos de la complejidad asintótica del peor de los casos, tanto para el tiempo como para el espacio, porque el producto óptimo puede estar a[0]
con cualquiera de los n-(k+1)
elementos en la distancia, al menos k+1
, por lo n-(k+1)
que cualquier algoritmo que resuelva el problema debe leer al menos los enteros.
La idea detrás del algoritmo es la siguiente:
El producto óptimo utiliza dos elementos de a
, suponga que estos son a[r]
y a[s]
. Sin pérdida de generalidad podemos suponer que s > r
dado que el producto es conmutativo.
Debido a la restricción, abs(s-r) > k
esto implica que s >= k+1
. Ahora s
podría ser cada uno de los índices que satisfagan esta condición, por lo que iteramos sobre estos índices. Esa es la iteración i
en el código que se muestra, pero se cambia por k+1
conveniencia (realmente no importa). Para cada iteración, necesitamos encontrar el producto óptimo que incluya el i+k+1
mayor índice y compararlo con la mejor estimación anterior.
Los índices posibles para emparejar i+k+1
son todos índices menores o iguales i
debido al requisito de distancia. Tendríamos que repetir todo esto también, pero eso es innecesario porque el mínimo de a[i+k+1]*a[j]
over j
en fijo i
es igual a min(a[i+k+1]*max(a[j]), a[i+k+1]*min(a[j]))
debido a la monotonicidad del producto (tomando el mínimo con respecto al mínimo y al máximo sobre a[j]
cuentas para los dos posibles signos de, a[i+k+1]
o equivalentemente, las dos posibles direcciones de monotonicidad.)
Dado que el conjunto de a[j]
valores sobre el que optimizamos aquí es justo {a[0], ..., a[i]}
, que simplemente crece por un elemento ( a[i]
) en cada iteración de i
, simplemente podemos realizar un seguimiento de max(a[j])
y min(a[j])
con variables individuales actualizándolas si a[i]
es mayor o menor que los valores óptimos anteriores. Esto se hace con back_max
y back_min
en el ejemplo de código.
El primer paso de la iteración ( i=0
) se omite en el bucle y, en su lugar, se realiza como inicialización de las variables.
std::vector
? @Scheff: la clasificación destruiría las relaciones originales de "distancia".