Algoritmo para unir números con un número mínimo de movimientos

11

Esta es una especie de pregunta de edición de distancia, y es muy fácil. Estoy completamente muerto de cerebro sobre este tema y no puedo entenderlo hasta ahora.


Dada una serie de números, por ejemplo

[3, 1, 1, 1]

¿Cómo podría uno convertir más eficientemente todos los números en el mismo número, con el número mínimo de "movimientos"? Por "mover" se entiende agregar o eliminar uno de un número.

En el ejemplo anterior, los movimientos más eficientes serían:

[1, 1, 1, 1]

Esto requeriría 2 movimientos, reduciendo el primer número dos veces.

No puedo encontrar la mejor manera de averiguarlo, dados conjuntos mucho más grandes de cientos de números.

Originalmente intenté calcular el número promedio redondeado (suma de todos divididos por la longitud), y luego reducirlos al promedio calculado, pero el ejemplo anterior rompió esto, requiriendo 4 movimientos en lugar de 2.

Supongo que podría imaginar:

  1. La media,
  2. El modo,
  3. La mediana

y obtenga la distancia de edición de cada uno de ellos, eligiendo la distancia mínima. Sin embargo, no estoy seguro de que esto sea correcto en cada caso. ¿Cómo puedo yo saber?

dthree
fuente
Si el dominio es limitado, puede probar todas las posibilidades desde mín. Hasta máx. De lo contrario, puede intentar usar el modo o la mediana.
Bartosz Przybylski
Gracias @ Bartek. Parece que probar todas las posibilidades sería tremendamente ineficiente si se tratara con cientos o miles de números. Comprobaré el modo / mediana. Pero, ¿están seguros de producir resultados en cada caso? Esa es mi pregunta principal. Estoy buscando un cierto algoritmo eficiente.
dthree
¿El número tiene que estar en el conjunto de números, o puede ser cualquier número entero?
TCSGrad
@TCSGrad Puede ser cualquier número entero, pero obviamente querrá elegir uno que esté entre el número mínimo y máximo. En este caso, ya sea 1, 2 o 3.
dthree

Respuestas:

10

La respuesta es tomar la mediana. Una de las propiedades de la mediana es que minimiza la distancia L1 a cada elemento. (Para dar sentido al artículo de Wikipedia, tome la distribución de probabilidad como la distribución uniforme sobre su serie original de números).

Este es el algoritmo que resuelve el problema (originalmente escrito por dc2 ):

function median(arr) {
  arr.sort(function(a, b) { return a - b; });
  var half = floor(arr.length/2);
  if ( arr.length % 2 ) {
    return arr[half];
  } else {
    return (arr[half-1] + arr[half]) / 2.0;
  }
}

function minl1(arr) {
  var moves = 0;
  var mdn = median(arr);
  for ( var i = 0; i < arr.length; ++i ) {
    moves += Math.abs(mdn - arr[i]);
  }
  return moves;
}

minl1([3, 1, 1, 1]); // -> 2
mhum
fuente
Si, eso lo hizo. Es curioso cómo funciona eso. No parece que la mediana lo haga, pero bueno. Muchas gracias.
Tres de
1
Vea mi respuesta para una prueba.
Yuval Filmus
@ dc2: No puedes "asegurarte" "probándolo".
Raphael
1
Solo para tener en cuenta: puede calcular el tiempo medio de O (n)
Bartosz Przybylski
1
@Raphael ¿Está bien incluir el código de OP en alguna otra respuesta, sin referencia a OP?
thefourtheye
10

Como menciona TCSGrad, dada una lista de enteros , está buscando el entero minimizando Es instructivo calcular : Cuando va de a , la cantidad va de a . Además, cambia los valores solo en los puntosx1,,xnm

δ(m)=i=1n|mxi|.
δ(m+1)δ(m)
δ(m+1)δ(m)=i=1n{+1mxi1m<xi=#{i:mxi}#{i:m<xi}.
m+δ(m+1)δ(m)nnx1,,xn. No es difícil comprobar que un valor óptimo de es el punto mínimo en el que . Este punto mínimo es uno de los , por lo que la distancia de edición es .mδ(m+1)δ(m)0ximin(δ(x1),,δ(xn))

Supongamos además que todos son distintos y que es impar. Sea la mediana de . Entonces mientras , y entonces es el óptimo único. Si es par, un cálculo similar muestra que podemos elegir cualquier punto en el intervalo que conecta las medianas. Un razonamiento similar pero más elaborado muestra que cualquier mediana es óptima incluso cuando no son distintos. Por lo tanto, no hay necesidad de calcular en todo .xinmxiδ(m+1)δ(m)=1δ(m)δ(m1)=1mnxiδxi

Yuval Filmus
fuente
Es posible que se lo haya perdido, pero esta respuesta (casi) prueba que la mediana es la opción óptima.
Yuval Filmus
1
Su respuesta fue excelente y la voté. Desafortunadamente para mí, un poco demasiado excelente, ya que no estoy muy versado en notación científica, dejando la mayor parte como algo ilegible. Ese es mi problema, no el tuyo.
dthree
5

El problema puede formularse como un problema de LP:

Dado un conjunto de números , resuelve el siguiente LP:n[a1,a2...an]

min|aix|

(Se eliminaron las restricciones en , que no eran necesarias como señaló Raphael)x

Una vez que se resuelve el LP, obtendrá un valor de correspondiente a la solución. Si es un entero, ya está listo; de lo contrario, redondee al entero más cercano.xx

EDITAR : Como se señaló en los comentarios, la función objetivo debe ser la suma de las diferencias absolutas. Para transformarlo nuevamente en un LP estándar, podemos reescribir el LP como:

minai

sujeto a:

aiaix i
aiaix i
ai,x0 i

En la solución óptima, , y podemos obtener el valor de de la solución.ai=|aix| ix

TCSGrad
fuente
Entonces, si entiendo esto correctamente, en mi ejemplo, x sería 1 - 3, y entonces encontraría la distancia de edición de 1, 2 y 3, y luego haría un minuto sobre eso.
Tres de
@ dc2: Esto minimizaría la suma de las distancias entre cada número y , donde es el número convergente. ¡Las restricciones aseguran que el LP termine rápidamente y no busque todos los enteros! xx
TCSGrad
¿Por qué son necesarias las restricciones?
Raphael