가장 가까운 거리의 합을 구합니다


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 Garf Hunter 17

@CatWizard 그렇습니다!
Anush

1
어떻게 1 + 2 + 3에서 유래 X = (1,2,3)Y = (0,8)?
guest271314

1
@ guest271314 가장 가까운 두 번째의 각 1, 23에서 YIS 0. 따라서 차이가 1-0, 2-0, 3-0.
dylnan

1
두 목록 정렬되기 때문에 @FreezePhoenix 당신은 당신으로 반복하기 때문에 목록을 통해, (N + m) O에서 할 수있는 번 각 요소를 방문, 그리고 당신이 요소의 추적 유지로 Y의 J 에 가장 가까운 X 전을 수행 할 수 있습니다 그 중 하나가 X i + 1에 가장 엑스와이제이엑스나는와이제이와이제이+1엑스나는+1
Giuseppe

답변:


6

하스켈 , 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)

여기서부터 첫 번째 경우 de:_와 바인딩 합니다 e:_<-d. 이렇게하면 d비어 있지 않고 첫 번째 요소가로 설정됩니다 e.

두 번째 요소이면 ( ) (제 가장 가까운 첫 번째 요소) X ( ), 우리 반환 의 첫 번째 요소 제거 Y를 동일한 다시 호출 X .와이ec엑스ax#d와이엑스

패턴과 일치하지만 조건을 전달하지 않으면 다음을 수행합니다.

a%c+b#y

이는 첫 번째 항목 제거 그리고 최초의 요소로부터 그 차분 절대 추가 X 나머지 결과로한다.엑스엑스

마지막으로 패턴과 일치하지 않으면 을 반환 합니다. 패턴과 일치 하지 않으면 Y 는 비워 질 수 없으므로 X 는 비어 있어야합니다 .0엑스와이

이 알고리즘에는 순서 표기법 있습니다.영형(|엑스|+|와이|)

하스켈 , 34 바이트

다음은 시간에 수행하는 방법입니다.영형(|엑스|×|와이|)

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

온라인으로 사용해보십시오!


두 정수를 추가하는 데 일정한 시간이 걸리는 것으로 가정 할 수 있다는 질문에 명확하게 설명했습니다.
Anush

2

파이썬 2 , 124120 바이트

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).


두 정수를 추가하는 데 일정한 시간이 걸리는 것으로 가정 할 수 있다는 질문에서 분명히 설명했습니다.
Anush

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도달하면 0(그리고이 b아래에서 감소 될 수 없다 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
;}

몇 가지 참고 사항 :

  • 배열을 인덱싱하는 대신 포인터를 늘리고 역 참조하면 가치가있을만큼 충분한 바이트가 절약됩니다 ( *xvs x[a]y[1]vs y[b+1]).

  • --b&&에 대한 조건을 확인 b>1로터리 방식으로는 - 경우 b입니다 1, 그것은 0으로 평가합니다. 이것이 수정되었으므로 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}

이 코드의 작동 방식을 간단한 용어로 설명해 주시겠습니까? 선형 시간으로 실행되는지 알 수 없습니다.
Anush

2
이것은 질문의 첫 번째 테스트 사례와 같은 입력에 실패합니다 [5, 6], [0, 1, 5].
손잡이

0

자바 스크립트 (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경우 falsy입니다 x[i]그렇지 않으면 범위 truthy 벗어
  • t다음 조건이 충족되는 한 -> d>y[j+1]-v-> v+v>y[j]+y[j+1]는 false입니다. 그리고 이것은 y[j]가장 가까운 숫자 v입니다.y
    • v보다 작 (y[j]+y[j+1])/2거나
    • y[j+1]범위를 벗어났습니다.로 변환 NaN하고 NaN수익률 과 비교합니다.false
      • 그래서 우리는 >1 바이트를 더 절약하기 위해 부호를 뒤집을 수 없습니다
  • t항상 부울 값이며 계산하기 전에 / *로 변환하십시오.01

온라인으로 사용해보십시오!


0

Mathematica, 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 포인트 (1 만마다 샘플링)에 대한 타이밍입니다 y.

여기에 이미지 설명을 입력하십시오

선형에 가깝습니다.


1
이 답변은 입력이 기존 변수로 사용되므로 코드 스 니펫입니다. 서브 루틴 또는 전체 프로그램으로 재 포맷해야합니다.
Ad Hoc Garf Hunter 1

나는 이것이 선형 시간으로 작동한다는 것이 약간 의심 스럽습니다. 왜 그럴 필요가 있는지에 대한 정당성이 있습니까? Mathematica는 내장의 복잡성에서 다소 불투명 한 경향이 있습니다.
Ad Hoc Garf Hunter 2
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.