Trova la somma delle distanze più vicine


10

Per questa attività il codice dovrebbe prendere due matrici ordinate di numeri interi X e Y come input. Dovrebbe calcolare la somma delle distanze assolute tra ciascun numero intero in X e il suo numero più vicino in Y.

Esempi:

X = (1 5,9)
Y = (3,4,7)

La distanza è 2 + 1 + 2.

X = (1,2,3)
Y = (0,8)

La distanza è 1 + 2 + 3.

Il tuo codice può ricevere input in qualsiasi modo sia conveniente.

La restrizione principale è che il codice deve essere eseguito in tempo lineare nella somma della lunghezza dei due array. . (Si può presumere che l'aggiunta di due numeri interi richieda un tempo costante.)


Possiamo usare elenchi o stream invece di array?
Ad Hoc Garf Hunter

@CatWizard Sì, puoi!
Anush,

1
Come viene 1 + 2 + 3derivato da X = (1,2,3)e Y = (0,8)?
guest271314

1
@ guest271314 più vicino numero due ciascuno dei 1, 2ed 3in YIS 0. Così le differenze sono 1-0, 2-0, 3-0.
dylnan,

1
@FreezePhoenix poiché entrambi gli elenchi sono ordinati, è possibile farlo in O (n + m), perché si scorre l'elenco , visitando ogni elemento una volta e finché si tiene traccia dell'elemento Y j più vicino a X i , è possibile controlla contro Y j e Y j + 1 poiché uno di questi è il più vicino a X i + 1XYjXioYjYj+1Xio+1
Giuseppe

Risposte:


6

Haskell , 70 64 byte

a%b=abs$a-b
x@(a:b)#y@(c:d)|e:_<-d,a%c>a%e=x#d|1>0=a%c+b#y
_#_=0

Provalo online!

Spiegazione

Per prima cosa definiamo (%)la differenza assoluta tra due numeri. Quindi definiamo (#)la funzione interessante. Nella prima riga corrispondiamo quando entrambe le liste non sono vuote:

x@(a:b)#(c:d:e)

Al nostro primo caso da qui ci leghiamo da e:_con e:_<-d. Questo assicura che dnon sia vuoto e imposti il ​​suo primo elemento su e.

Quindi se il secondo elemento di ( ) è più vicino del primo ( ) al primo elemento di X ( ), si ritorna rimozione del primo elemento di Y e chiamando nuovamente con la stessa X .YecXax#dYX

Se abbiniamo lo schema ma non superiamo la condizione che facciamo:

a%c+b#y

Il che rimuove il primo elemento di e aggiunge la differenza assoluta dal primo elemento di X al risultato rimanente.XX

Infine, se non corrispondiamo al modello, restituiamo . Non corrispondere al modello significa che X deve essere vuoto perché Y non può essere vuoto.0XY

Questo algoritmo ha la notazione dell'ordine .O(|X|+|Y|)

Haskell , 34 byte

Ecco come lo farei in volta:O(|X|×|Y|)

x#y=sum[minimum$abs.(z-)<$>y|z<-x]

Provalo online!


Ho chiarito nella domanda che possiamo supporre che l'aggiunta di due numeri interi richieda un tempo costante.
Anush,

2

Python 2 , 124 120 byte

X,Y=input()
i=j=s=0
while i<len(X):
 v=abs(Y[j]-X[i])
 if j+1<len(Y)and v>=abs(Y[j+1]-X[i]):j+=1
 else:s+=v;i+=1
print s

Provalo online!

Salvati 4 byte passando al programma rispetto alla funzione.

Soddisfare il vincolo di complessità temporale è possibile perché entrambi gli elenchi sono ordinati. Si noti che ogni volta intorno al ciclo, iviene incrementato o jincrementato. Pertanto il loop viene eseguito il più delle len(X)+len(Y)volte.


Ho chiarito nella domanda che possiamo supporre che l'aggiunta di due numeri interi richieda un tempo costante.
Anush,

1

C (gcc), 82 byte

n;f(x,y,a,b)int*x,*y;{for(n=0;a;)--b&&*x*2-*y>y[1]?++y:(++b,--a,n+=abs(*x++-*y));}

Questo prende input come due array interi e le loro lunghezze (poiché C non ha modo di ottenere la loro lunghezza altrimenti). Questo può essere eseguito O(a+b)perché ao bè decrementato su ogni iterazione del ciclo, che termina quando araggiunge 0(e bnon può essere decrementato di seguito 0).

Provalo online!

n;                     // define sum as an integer
f(x,y,a,b)             // function taking two arrays and two lengths
int*x,*y;              // use k&r style definitions to shorten function declaration
{
 for(n=0;              // initialize sum to 0
 a;)                   // keep looping until x (the first array) runs out
                       // we'll decrement a/b every time we increment x/y respectively
 --b&&                 // if y has ≥1 elements left (b>1, but decrements in-place)...
 *x*2-*y>y[1]?         // ... and x - y > [next y] - x, but rearranged for brevity...
 ++y:                  // increment y (we already decremented b earlier);
 (++b,                 // otherwise, undo the in-place decrement of b from before...
 --a,n+=abs(*x++-*y))  // decrement a instead, add |x-y| to n, and then increment x
;}

Alcune note:

  • Invece di indicizzare nelle matrici, incrementare i puntatori e la dereferenziazione salva direttamente abbastanza byte per valerne la pena ( *xvs x[a]e y[1]vs y[b+1]).

  • La --b&&condizione verifica b>1in modo rotatorio - se lo bè 1, verrà valutata a zero. Poiché questo modifica b, non abbiamo bisogno di cambiarlo nel primo ramo del ternario (che avanza y), ma dobbiamo cambiarlo nel secondo (che avanza x).

  • Non returnè necessaria alcuna dichiarazione, perché la magia nera. (Penso che sia perché l'ultima istruzione da valutare sarà sempre l' n+=...espressione, che utilizza lo stesso registro di quello usato per i valori di ritorno.)


0

Rubino, 88 byte

->(p,q){a=q.each_cons(2).map{|a|a.sum/a.size}
x=a[0]
p.sum{|n|x=a.pop if n>x
(n-x).abs}}

Provalo online!

Inoltre, per divertimento, una funzione anonima più breve che non soddisfa del tutto le restrizioni di complessità:

->(a,b){a.map{|x|x-b.min_by{|y|(x-y).abs}}.sum}

Potresti spiegare in termini semplici come funziona questo codice? Non so dire se funziona in tempo lineare.
Anush,

2
Questo fallisce il primo caso di test nella domanda, così come input come [5, 6], [0, 1, 5].
Maniglia della porta

0

JavaScript (Node.js) , 80 byte

x=>g=(y,i=0,j=0,v=x[i],d=v-y[j],t=d>y[j+1]-v)=>1/v?g(y,i+!t,j+t)+!t*(d>0?d:-d):0
  • Funziona in O (| X | + | Y |): ogni ricorsione viene eseguita in O (1) e ricorsiva | X | + | Y | volte.
    • x, yvengono passati per riferimento, che non copia il contenuto
  • 1/vè falso se x[i]è fuori portata, in verità altrimenti
  • t-> d>y[j+1]-v-> v+v>y[j]+y[j+1]è falso purché siano soddisfatte le seguenti condizioni. E ciò significa che y[j]è il numero più vicino a viny
    • vè inferiore a (y[j]+y[j+1])/2, o
    • y[j+1]non rientra nell'intervallo, che verrebbe convertito in NaN, e confrontato con il NaNrendimentofalse
      • ecco perché non possiamo capovolgere il >segno per salvare un altro byte
  • tè sempre un valore booleano e lo *converte in 0/ 1prima del calcolo

Provalo online!


0

Mathematica, 40 byte

x = {1, 5, 9};
y = {3, 4, 7};

Norm[Flatten[Nearest[y] /@ x] - x]

Se è necessario creare un programma completo, con input:

f[x_,y_]:= Norm[Flatten[Nearest[y] /@ x] - x]

Ecco i tempi per un massimo di 1.000.000 di punti (campionati ogni 10.000) per y:

inserisci qui la descrizione dell'immagine

Vicino a lineare.


1
Questa risposta è uno snippet di codice poiché il tuo input viene preso come variabili preesistenti. Dovresti riformattarlo in una sub-routine o in un programma completo.
Ad Hoc Garf Hunter

Sono anche un po 'sospettoso che funzioni in tempo lineare, hai qualche giustificazione sul perché dovrebbe? Mathematica tende ad essere piuttosto opaca nella complessità dei suoi builtin.
Ad Hoc Garf Hunter
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.