두 배열에서 다른 하나의 요소입니다. 효율적으로 찾는 방법?


22

코딩 인터뷰를 준비 중이며이 문제를 해결하는 가장 효율적인 방법을 알 수 없습니다.

정렬되지 않은 숫자로 구성된 두 개의 배열이 있다고 가정 해 봅시다. 배열 2에는 배열 1에없는 숫자가 포함됩니다. 두 배열 모두 반드시 같은 순서로 또는 같은 인덱스에있는 숫자가 무작위로 없습니다. 예를 들면 다음과 같습니다.

배열 1 [78,11, 143, 84, 77, 1, 26, 35 .... n]

배열 2 [11,84, 35, 25, 77, 78, 26, 143 ... 21 ... n + 1]

다른 수를 찾는 가장 빠른 알고리즘은 무엇입니까? 러닝 타임은? 이 예에서 찾고자하는 숫자는 21입니다.

내 생각은 배열 1을 실행하고 배열 2에서 해당 값을 삭제하는 것이 었습니다. 완료 할 때까지 반복하십시오. 대략 실행 시간 이어야합니다 .O(nlogn)


@Jandvorak 답변 주셔서 감사합니다. 나는 늦었고 이것을 게시 한 후 잠 들었다. 배열이 정렬되지 않고 모든 항목이 두 배열 모두에서 임의의 인덱스로 나타납니다.
Konstantino Sparakis 2016

@ KonstantinoSparakis :이 설명은 두 배열 모두 같은 위치에 요소가 있다고 가정하는 대답을 무효화합니다.
Mario Cervera

cross
paparazzo

@Paparazzi는 단순히 메타 소프트웨어 엔지니어링에서 읽은 솔루션을 찾고 있었지만 솔루션을 얻을 수있는 곳 이었지만 CS 포럼에 대해서는 알지 못했습니다. 나는 모드를 정리하여 정리했다.
Konstantino Sparakis 2014

@Paparazzi는 그것을 백업하는 메타 포스트가 있습니까? 나는 개인적으로 그 정책을 잘 이행 할 방법이 없다.
djechlin

답변:


30

다른 실행 시간 으로이 문제를 해결하는 네 가지 주요 방법이 있습니다.

  • NO(n2) 솔루션 : 제안한 솔루션입니다. 배열이 정렬되지 않았으므로 삭제에 선형 시간이 걸립니다. 삭제를 수행합니다 . 따라서이 알고리즘은 2 차 시간이 걸립니다.n

  • O ( nO(nlogn) 솔루션 : 미리 배열을 정렬합니다. 그런 다음 선형 검색을 수행하여 고유 한 요소를 식별하십시오. 이 솔루션에서 실행 시간은 정렬 작업에 의해 좌우되므로 상한입니다.O(nlogn)

문제에 대한 해결책을 찾을 때 항상 스스로에게 자문을 구해야합니다. 더 잘할 수 있습니까? 이 경우 데이터 구조를 영리하게 사용할 수 있습니다. 한 배열을 반복하고 다른 배열에서 반복 조회를 수행하기 만하면됩니다. 일정한 시간 내에 어떤 데이터 구조로 조회를 수행 할 수 있습니까? 당신은 옳았다 : 해시 테이블 .

  • O(n) 솔루션 (예상) : 첫 번째 배열을 반복하고 요소를 해시 테이블에 저장합니다. 그런 다음 두 번째 배열에서 선형 스캔을 수행하여 해시 테이블의 각 요소를 찾습니다. 해시 테이블에서 찾을 수없는 요소를 리턴하십시오. 이 선형 시간 솔루션은 해시 함수에 전달할 수있는 모든 유형의 요소에 적용됩니다 (예 : 문자열 배열에 대해서도 유사하게 작동 함).

상한 보증을 원하고 배열이 정수로 엄격하게 구성된 경우 가장 좋은 해결책은 아마도 Tobi Alafin이 제안한 것입니다 (이 솔루션은 두 번째 배열에서 다른 요소의 색인을 제공하지는 않지만) :

  • O(n) 해 (보장) : 첫 번째 배열의 요소를 요약합니다. 그런 다음 두 번째 배열의 요소를 요약하십시오. 마지막으로 빼기를 수행하십시오. 비트 XOR 연산자 덕분에이 솔루션은 실제로 값을 고정 길이 비트 문자열로 표현할 수있는 모든 데이터 유형으로 일반화 될 수 있습니다 . 이것은 Ilmari Karonen의 답변 에 철저히 설명되어 있습니다.

마지막으로, 정수 배열의 동일한 가정 하에서 다른 가능성은 계수 정렬과 같은 선형 시간 정렬 알고리즘을 사용하는 것입니다. 이는 정렬 기반 솔루션의 실행 시간을 에서 입니다.O ( n )O(nlogn)O(n)


4
그러나 숫자가 충분히 커지면 합산은 선형이 아닙니다.
Sarge Borsch 2016

9
합산 알고리즘의 한 가지 좋은 점은 정수뿐만 아니라 모든 아벨 uint64리아 그룹과도 작동한다는 것입니다 (주로 ; cc @sarge).
John Dvorak

6
@Abdul는 정수가 매우 큰 경우 더 이상 를 더하는 척 할 수 없습니다 . 당신이 그것을 설명한다면 복잡성이 O ( n ln n )로 증가한다고 생각합니다 . 그러나 일반적인 덧셈 대신 XOR을 사용하면 여전히 많은 수의 입력을 허용하면서 문제를 해결합니다. O(n)O(nlnn)
John Dvorak

2
@JanDvorak 아니요, 그렇지 않습니다. 당신은 abelian 그룹에 정의 된 작업이 일정한 시간이 걸린다고 가정합니다. 그냥 가정 할 수 없습니다.
UTF-8

2
@ UTF-8 나는 그것을 가정하지 않습니다. 그러나 유한 그룹 (uint64)에서는 그렇게하고 자리 내 자리 추가 ( )는 위치 외 피연산자의 크기가 선형입니다. 따라서, 이러한 그룹의 합을 계산하는 단계 이다 피연산자의 전체 크기에 선형 시간. Znd
John Dvorak

16

용액 제안 차분의 합 - 도비마리오 사실 우리가 (일정 시간) 이진 동작을 정의 할 수있는 다른 데이터 유형에 일반화 될 수있다 이다 :Θ(n)

  • 같은 임의 값 것을 및 B , ⊕의 B가 정의되어 동일한 종류 (또는 조작자가되는 그 어떤 적절한 퍼의 적어도 여전히 정의된다);abab
  • 회합 , 예컨대 그 ( B C ) = ( B ) C ;a(bc)=(ab)c
  • 가환 ,되도록 B = B ; 과ab=ba
  • cancellative 역 연산자가 존재하도록 만족 ( ⊕의 B ) B = . 기술적으로,이 역 연산은 n 개의 요소 의 두 합을 "감산"하는 데 각각 O ( n ) 시간을 초과하지 않는 한 반드시 일정한 시간 일 필요 는 없습니다 .(ab)b=anO(n)

(유형이 유한 한 수의 고유 값만 취할 수있는 경우, 이러한 특성은 Abelian 그룹 으로 만들기에 충분합니다 . 그렇지 않은 경우에도 최소한 정류 가능한 반 정형 그룹이 됩니다.)

이러한 동작을 사용 우리는 어레이의 "합"을 정의 할 수 = ( 1 , 2 , ... , N ) 등을 ( a=(a1,a2,,an) 다른 배열이 주어 B = ( b를 1 , b를 2 , ... , B , N , B , N + 1 ) 의 모든 요소가 포함더한 추가 소자 (X)를 , 우리는 따라서이 (

(a)=a1a2an.
b=(b1,b2,,bn,bn+1)ax 이므로 다음과 같이 계산하여이 추가 요소를 찾을 수 있습니다. x = ( (b)=(a)x
x=(b)(a).

배열의 값이 정수가있는 경우 예를 들어, 또한 (또는 정수 모듈 또한 유한 길이의 정수 유형) 연산자로서 사용될 수있다 역 동작과 감산으로 . 또는 고정 길이 비트 문자열로 값을 나타낼 수있는 모든 데이터 유형에 대해 비트 XOR 모두로 사용할 수 있습니다 .

더 일반적으로, 우리는 끝에서 패딩을 가역적으로 제거 할 수있는 방법이있는 한 필요에 따라 같은 길이까지 패딩하여 가변 길이의 문자열에 비트 XOR 방법을 적용 할 수도 있습니다.

어떤 경우에는 사소한 일입니다. 예를 들어, C 스타일의 널 종료 바이트 문자열은 암시 적으로 자체 길이를 인코딩하므로이 방법을 적용하는 것은 쉽지 않습니다. 두 문자열을 XOR 할 때 짧은 문자열을 널 바이트로 채워 길이를 일치시키고 추가 후행 널을 자릅니다. 최종 결과. 중간 XOR 합계 문자열 에는 null 바이트 포함될 있으므로 길이를 명시 적으로 저장해야하지만 최대 한두 개만 필요합니다.

더 일반적으로, 임의의 비트 문자열에 대해 작동하는 한 가지 방법은 1 비트 패딩 을 적용하는 것입니다 . 여기서 각 입력 비트 열은 단일 비트로 채워진 다음 패딩 된 길이와 일치하는 데 필요한만큼의 0 비트로 채워집니다. 가장 긴 입력 문자열. (물론,이 패딩은 사전에 명시 적으로 수행 할 필요는 없습니다. XOR 합을 계산하는 동안 필요에 따라 적용 할 수 있습니다.) 마지막에 우리는 후행 0 비트와 마지막 1 비트 를 스트립에서 제거하면 됩니다. 결과. 또는 현이 예를 들어 최대 2 321001232바이트 길이가 길면 각 문자열의 길이를 32 비트 정수로 인코딩하여 문자열 앞에 붙일 수 있습니다. 또는 접두사 코드를 사용하여 임의의 문자열 길이를 인코딩 하고 문자열 앞에 붙일 수도 있습니다. 다른 가능한 인코딩도 존재합니다.

실제로, 컴퓨터에서 표현할 수있는 모든 데이터 유형은 정의에 따라 유한 길이의 비트 문자열로 표현 될 수 방법은 문제에 대한 일반적인 Θ ( n ) 솔루션을 생성합니다.Θ(n)

잠재적으로 까다로운 부분은 취소가 작동하기 위해 각 값에 대해 고유 한 정식 비트 열 표현을 선택해야한다는 것입니다. 이는 두 배열의 입력 값이 주어지면 어려울 수 있습니다 (실제로 계산할 수없는 경우도 있음) 다른 동등한 표현으로. 그러나 이것은이 방법의 특정한 약점이 아닙니다. 입력에 동등성을 결정할 수없는 값을 포함하도록 허용 된 경우이 문제점을 해결하는 다른 방법도 실패 할 수 있습니다.


와우 매우 흥미 롭습니다. 감사합니다 @IlmariKaronen
Konstantino Sparakis

14

Tobi의 답변에 대한 의견으로 이것을 게시했지만 아직 평판이 없습니다.

각 목록의 합계를 계산하는 대안 (특히 큰 목록이거나 합산 할 때 데이터 유형이 오버플로 될 수있는 매우 큰 숫자를 포함하는 경우) 대신 xor를 사용할 수 있습니다.

각 목록의 xor-sum (즉, x [0] ^ x [1] ^ x [2] ... x [n])을 계산 한 다음 두 값을 xor 계산하십시오. 이것은 당신에게 관계없는 아이템의 가치를 줄 것입니다 (그러나 색인은 아닙니다).

이것은 여전히 O (n) 이며 오버플로 문제를 피합니다.


3
XOR도 약간 깔끔해 보이기 때문에 XOR을 사용할 것입니다. 그러나 공평하게 말하면 오버플로는 실제로 구현하는 언어가 랩핑으로 오버플로를 지원하는 한 문제가되지 않습니다.
Martin Ender

14

요소 = 합 (배열 2)-합 (배열 1)

나는 진심 이 가장 최적의 알고리즘이다 의심한다. 그러나 그것은 문제를 해결하는 또 다른 방법이며, 그것을 해결하는 가장 간단한 방법입니다. 도움이 되길 바랍니다.

추가 된 요소 수가 둘 이상인 경우 작동하지 않습니다.

내 대답은 최고, 최악 및 평균 사례에 대해 동일한 런타임 복잡성을 가지고 있습니다.

편집
약간의 생각 후에, 내 대답은 당신의 해결책이라고 생각합니다.

nn11=n12=n+11=n

2n121=1

2n1+1=2n

Θ(n)

편집 :
데이터 유형에 문제가 있기 때문에 reffu 제안한 XOR 합계 가 더 적합합니다.


숫자를 합하면 반올림 오류가 발생할 수 있으므로이 방법은 값이 부동 소수점 인 경우 정확한 답을 얻지 못할 수 있습니다. 그러나 a) 정수 유형에 오버플로시 랩 어라운드 동작이 잘 정의되어 있거나 b) 오버플로 할 수없는 유형의 변수에 합계를 저장하면 정수 값에 대해 작동합니다.
Ilmari Karonen

루비의 "BigNum"클래스가이를 처리 할 수 ​​있습니다.
Tobi Alafin

배열에 예를 들어 문자열이 있거나 의미있게 추가 할 수없는 것이 포함되어 있으면 절대 작동하지 않습니다.
gnasher729

그래, 나는 깨달았다. 'XOR'을 사용하는 것은 어떻습니까? 수레에서 작동합니까?
Tobi Alafin

예. 또한 포인터 및 일반적으로 고정 숫자 비트로 구성된 모든 것. 많은 언어가이를 지원하지 않지만 근본적인 문제는 아닙니다. 모듈 식 더하기 / 빼기는 같은 경우에 작동합니다.
해롤드

1

배열 1을 취하여 임의의 위치에 요소를 삽입하여 배열 2를 작성했다고 가정하거나 배열 2를 취하여 임의의 요소를 삭제하여 배열 1을 작성했다고 가정하십시오.

모든 배열 요소가 구별되도록 보장되는 경우 시간은 O (ln n)입니다. n / 2 위치의 요소를 비교합니다. 동일하면 추가 요소는 n / 2 + 1에서 배열 끝까지이며, 그렇지 않으면 0에서 n / 2입니다. 등등.

배열 요소가 구별되지 않는 경우 : 배열 1에서 숫자 1의 n 배와 배열 2의 임의의 위치에 숫자 2를 삽입 할 수 있습니다.이 경우 숫자 2가 어디에 있는지 전혀 알 수 없습니다. 배열 요소. 따라서 O (n).

추신. 요구 사항이 변경되었으므로 라이브러리에서 사용 가능한 항목을 확인하십시오. macOS / iOS에서 NSCountedSet을 생성하고, 배열 2에서 모든 숫자를 추가하고, 배열 1에서 모든 숫자를 제거하며, 남은 것은 배열 1에는 없지만 배열 1에는없는 모든 것이 하나 더 있다는 주장에 의존하지 않고 목.


이 답변은 발견되었지만 귀하의 가정을 무효화하는 새로운 요구 사항으로 질문이 편집되었습니다.
Mario Cervera

당신의 새로운 답변이 옳은 것 같습니다. 시간 복잡성이란 무엇입니까?
Tobi Alafin

먼저 코드를 작성하는 데 필요한 시간은 얼마입니까? 사소한 일입니다. NSCountedSet은 해싱을 사용하므로 시간 복잡성은 "보통 선형"입니다.
gnasher729

-1

var는 가장 짧고 가장 길다.

빠른 참조를 위해 가장 짧은 맵으로 변환하고 현재 값이 맵에 없을 때까지 가장 긴 루프를 반복하십시오.

자바 스크립트에서 이와 같은 것 :

if (arr1.length> arr2.length) {최단 = arr2; 가장 긴 = arr1; } else {최단 = arr1; 가장 긴 = arr2; }

var map = shortest.reduce (function (obj, value) {obj [value] = true; 반환 obj;}, {});

var difference = longest.find (function (value) {return !!! map [value];});


설명이없는 코드는 여기서 좋은 대답으로 간주되지 않습니다. 또한 왜 사용하겠습니까 !!! ?
Evil

-1

시간 복잡도의 O (N) 솔루션 공간 복잡성 측면에서 O (1)

문제 설명 : array2에 array1의 모든 요소와 array1에없는 다른 요소가 있다고 가정합니다.

해결책은 다음과 같습니다. xor를 사용하여 array1에없는 요소를 찾습니다. 단계는 다음과 같습니다. 1. array1에서 시작하여 모든 요소의 xor를 수행하여 변수에 저장합니다. 2. array2를 가져와 array1의 xor를 저장하는 변수로 모든 요소의 xor를 수행하십시오. 3. 연산을 수행 한 후 변수에는 array2에만있는 요소가 포함됩니다. 위의 알고리즘은 xor "a xor a = 0" "a xor 0 = a"의 다음 속성 때문에 작동합니다. 이것이 문제를 해결하기를 바랍니다. 또한 위의 제안 된 솔루션도 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.