Algoritmo para combinar números com número mínimo de movimentos

11

Esse é um tipo de pergunta de distância de edição e é muito fácil. Estou com morte cerebral bastante neste assunto e não consigo descobrir até agora.


Dada uma série de números, por exemplo

[3, 1, 1, 1]

Como alguém transformaria todos os números de maneira mais eficiente no mesmo número, com o número mínimo de "movimentos"? "Mover" significa adicionar ou remover um de um número.

No exemplo acima, as jogadas mais eficientes seriam:

[1, 1, 1, 1]

Isso exigiria 2 movimentos, reduzindo o primeiro número duas vezes.

Não consigo descobrir a melhor maneira de descobrir isso, considerando matrizes muito maiores de centenas de números.

Inicialmente, tentei calcular o número médio arredondado (soma de todos os divididos pelo comprimento) e reduzi-los à média calculada, mas o exemplo acima quebrou isso, exigindo 4 movimentos em vez de 2.

Suponho que poderia imaginar:

  1. A média,
  2. O modo,
  3. A mediana

e obtenha a distância de edição de cada um deles, escolhendo a distância mínima. No entanto, não tenho certeza de que isso esteja correto em todas as instâncias. Como posso saber?

dthree
fonte
Se o domínio é limitado, você pode tentar todas as possibilidades, de min a max. Caso contrário, você pode tentar usar o modo ou a mediana.
Bartosz Przybylski
Obrigado @Bartek. Parece que tentar todas as possibilidades seria tremendamente ineficiente se lidássemos com centenas ou milhares de números. Vou verificar o modo / mediana. Mas estes certamente produzirão resultados em todos os casos? Essa é a minha pergunta principal. Eu estou procurando por um algoritmo certo e eficiente.
dthree
O número precisa estar no conjunto de números ou pode ser qualquer número inteiro?
TCSGrad
@TCSGrad Pode ser qualquer número inteiro, mas obviamente você gostaria de escolher um que esteja entre o número mínimo e o máximo. Nesse caso, 1, 2 ou 3.
dthree

Respostas:

10

A resposta é levar a mediana. Uma das propriedades da mediana é que ela minimiza a distância L1 de cada elemento. (Para entender o artigo da Wikipedia, considere a distribuição de probabilidade como sendo a distribuição uniforme sobre sua série original de números).

Este é o algoritmo que resolve o 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
fonte
Sim, foi isso. Engraçado como isso funciona. Não parece que a mediana faria isso, mas ei. Muito obrigado.
dthree
1
Veja minha resposta para uma prova.
Yuval Filmus
@ DC2: Você não pode "ter certeza" de "experimentá-lo".
Raphael
1
Só para nota: você pode calcular O mediana (n)
Bartosz Przybylski
1
@ Rafael É correto incluir o código do OP em alguma outra resposta, sem fazer referência ao OP?
thefourtheye
10

Como o TCSGrad menciona, dada uma lista de números inteiros , você está procurando o número inteiro m que minimiza δ ( m ) = n i = 1 | m - x i | . É instrutivo calcular δ ( m + 1 ) - δ ( m ) : δ ( m + 1 ) - δ ( m ) =x1,,xnm

δ(m)=i=1n|mxi|.
δ(m+1)δ(m) Comomvai de-a+, a quantidadeδ(m+1)-δ(m)
δ(m+1)δ(m)=i=1n{+1mxi1m<xi=#{i:mxi}#{i:m<xi}.
m+δ(m+1)δ(m)vai de para n . Além disso, ele alterna valores apenas nos pontos x 1 , , x n . Não é difícil verificar se um valor ótimo de m é o ponto mínimo no qual δ ( m + 1 ) - δ ( m ) 0 . Esse ponto mínimo é um dos x i , portanto a distância de edição é mínima ( δ ( x 1 ) , , δ ( xnnx1,,xnmδ(m+1)δ(m)0xi .min(δ(x1),,δ(xn))

xinmxiδ(m+1)δ(m)=1δ(m)δ(m1)=1mnxiδxi

Yuval Filmus
fonte
Você pode ter perdido, mas essa resposta (quase) prova que a mediana é a melhor escolha.
Yuval Filmus
1
sua resposta foi excelente e eu a votei. Infelizmente para mim, um pouco excelente demais, pois não sou tão versado em notação científica, deixando a maior parte como se tornasse ilegível. Esse é o meu problema, não o seu.
dthree
5

O problema pode ser formulado como um problema de LP:

n[a1,a2...an]

min|aix|

x

xx

EDIT : Como apontado nos comentários, a função objetivo deve ser soma sobre diferenças absolutas. Para transformá-lo novamente em um LP padrão, podemos reescrevê-lo como:

minai

sujeito a:

aiaix i
aiaix i
ai,x0 i

ai=|aix| ix

TCSGrad
fonte
Então, se eu entendi isso corretamente, no meu exemplo, x seria 1 - 3, e então encontraria a distância de edição de 1, 2 e 3 e, em seguida, faria um mínimo nisso?
dthree
xx
Por que as restrições são necessárias?
Raphael