Знайдіть суму найближчих відстаней


10

Для цього завдання ваш код повинен взяти два впорядковані масиви цілих чисел X і Y як вхідні дані. Слід обчислити суму абсолютних відстаней між кожним цілим числом у X та його найближчим числом у Y.

Приклади:

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

Відстань 2 + 1 + 2.

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

Відстань - 1 + 2 + 3.

Ваш код може приймати інформацію будь-яким зручним способом.

Основне обмеження полягає в тому, що ваш код повинен працювати в лінійний час у сумі довжини двох масивів. . (Можна припустити, що додавання двох цілих чисел займає постійний час.)


Чи можна використовувати списки чи потоки замість масивів?
Ad Hoc Hunter Hunter

@CatWizard Так, ви можете!
Ануш

1
Як 1 + 2 + 3походить від X = (1,2,3)і Y = (0,8)?
гість271314

1
@ Guest271314 найближчий номер два кожен з 1, 2і 3в YІБ 0. Таким чином, відмінність 1-0, 2-0, 3-0.
ділнан

1
@FreezePhoenix, оскільки обидва списки відсортовані, ви можете зробити це в O (n + m), оскільки ви повторюєте список , відвідуючи кожен елемент один раз, і поки ви відстежуєте елемент Y j, найближчий до X i , ви можете перевірити проти Y j та Y j + 1, оскільки один із них найближчий до X i + 1XYjXiYjYj+1Xi+1
Джузеппе

Відповіді:


6

Haskell , 70 64 байт

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

Спробуйте в Інтернеті!

Пояснення

Спочатку визначимо (%)абсолютну різницю між двома числами. Тоді ми визначаємо (#)як цікаву функцію. У першому рядку ми співставляємось, коли обидва списки не порожні:

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

На нашому першому випадку з тут ми прив'язуємо dдо e:_з e:_<-d. Це гарантує, що dце не порожньо, і встановлює перший елемент e.

Тоді , якщо другий елемент ( ) ближче , ніж перший ( ) до першого елементу X ( ), ми повертаємо видалення першого елемента Y і повторний виклик з тим же X .YecXax#dYX

Якщо ми відповідаємо шаблону, але не передаємо умови, яку ми виконуємо:

a%c+b#y

XX

0XY

O(|X|+|Y|)

Хаскелл , 34 байти

O(|X|×|Y|)

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

Спробуйте в Інтернеті!


У запитанні я уточнив, що можна припустити, що додавання двох цілих чисел займає постійний час.
Ануш

2

Python 2 , 124 120 байт

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

Спробуйте в Інтернеті!

Збережено 4 байти, перейшовши на програму проти функції.

Дотримати обмеження за часовою складністю можливо, оскільки обидва списки відсортовані. Зауважте, що кожен раз навколо циклу або iзбільшується, або jзбільшується. Таким чином цикл виконується у більшості len(X)+len(Y)випадків.


У запитанні я уточнив, що можна припустити, що додавання двох цілих чисел займає постійний час.
Ануш

1

C (gcc), 82 байти

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));}

Це сприймає дані як два цілих масиви та їх довжину (оскільки C не має можливості отримати їх довжину в іншому випадку). Це може бути показано, що він працює, O(a+b)оскільки aабо bзменшується на кожній ітерації циклу, яка закінчується при aдосягненні 0bне може бути зменшена нижче 0).

Спробуйте в Інтернеті!

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
;}

Деякі примітки:

  • Замість того, щоб індексувати масиви, примноження покажчиків та перенаправлення безпосередньо економить достатню кількість байтів, щоб воно було вартим ( *xпроти x[a]і y[1]проти y[b+1]).

  • У --b&&перевіряє стан для b>1обхідним шляхом - якщо bє 1, то буде нульове значення. Оскільки це bзмінюється, нам не потрібно міняти його в першій гілці терміналу (яка просувається y), але нам потрібно змінити його назад у другій (яка просувається x).

  • Жодне returnтвердження не потрібно, бо чорна магія. (Я думаю, що це тому, що останнім оцінюваним твердженням завжди буде n+=...вираз, який використовує той же регістр, що і той, який використовується для повернення значень.)


0

Рубін, 88 байт

->(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}}

Спробуйте в Інтернеті!

Крім того, для розваги коротша анонімна функція, яка не зовсім відповідає обмеженням складності:

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

Чи можете ви пояснити простими словами, як працює цей код? Я не можу сказати, чи працює він у лінійний час.
Ануш

2
Це не вдається в першому тестовому випадку у запитанні, а також введеннях, таких як [5, 6], [0, 1, 5].
Дверна ручка

0

JavaScript (Node.js) , 80 байт

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
  • Він працює в O (| X | + | Y |): Кожен рекурсійний цикл в O (1), і він рекурсивний | X | + | Y | разів.
    • x, yпередаються шляхом посилання, які не копіюють вміст
  • 1/vє помилковим, якщо він x[i]знаходиться поза межами діапазону, правда в іншому випадку
  • t-> d>y[j+1]-v-> v+v>y[j]+y[j+1]помилково, якщо виконуються наступні умови. А що означає y[j]це число ближче до vвy
    • vменше (y[j]+y[j+1])/2, або
    • y[j+1]знаходиться поза діапазоном, який би конвертував NaNі порівнював із NaNурожайністюfalse
      • тому ми не можемо перевернути >знак, щоб зберегти ще 1 байт
  • tзавжди булеве значення, і *перетворити його в 0/ 1перед обчисленням

Спробуйте в Інтернеті!


0

Математика, 40 байт

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

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

Якщо вам потрібно створити повну програму, із вхідними даними:

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

Ось терміни набору до 1 000 000 балів (вибірки кожні 10 000) для y:

введіть тут опис зображення

Близький до лінійного.


1
Ця відповідь є фрагментом коду, оскільки ваш вклад приймається як попередні змінні. Вам слід переформатувати це як підпрограма, так і повна програма.
Спеціальний мисливець на Garf Garf

Я також трохи підозріло, що це працює в лінійний час, чи є у вас виправдання, чому це повинно? Математика, як правило, досить непрозора у складності своїх вбудованих елементів.
Спеціальний мисливець на Garf Garf
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.