O (n) 시간으로 : 비교가 전 이적이지 않은 세트에서 가장 큰 요소 찾기


21

제목은 질문을 말합니다.

우리는 입력으로 요소 목록을 가지고 있으며, 비교할 수 있습니다 ( 가장 큰 것을 결정하십시오 ). 어떤 요소도 같을 수 없습니다.

키 포인트:

  1. 비교는 전 이적이지 않습니다 (바위 가위를 생각하십시오) : 이것은 사실 일 수 있습니다 : A> B, B> C, C> A (여기에 유효한 답변이 없으므로 유효한 입력이 아닙니다. 비전 이적 비교 "의미)
  2. 각 입력 배열은 응답을 보장합니다
  3. 최대 는 요소 다른 모든 요소보다 커야 함을 의미합니다.
  4. 컨버스 속성 보유 예 : A> B는 B <A

예:

Input: [A,B,C,D]
A > B, B > C, C > A
D > A, D > B, D > C
Output: D

나는 O (n) 시간에 이것을 할 수있는 방법을 알 수 없으며 최선의 해결책은 O (n ^ 2)입니다.

나는 대답을 확실하게하기 위해 요소가 다른 모든 요소와 명시 적으로 비교되어야한다는 사실 때문에 모든 접근 방식에 갇혀 있습니다 (비교가 전 이적이지 않기 때문에).

이것은 힙 사용, 정렬 등을 배제합니다.


8
"가장 큰 요소"가 어떻게 정의 될지 불분명합니까? 예를 들어 ? 다른 비교 규칙이 있습니까? A>B,B>C,C>에이
fade2black

6
적어도 부분적으로 정렬되지 않은 세트에서 가장 큰 요소를 어떻게 선택하는지 상상할 수 없습니다. 가장 큰 요소와 가장 작은 요소 의 정의 를 참조하십시오 . 과도 성 부족은 부분적 순서를 배제합니다.
fade2black

3
@ fade2black 왜 나를 "가장 큰"의 다른 정의로 ​​연결합니까? 나는이 질문의 맥락에서 가장 큰 정의를 명시 적으로 언급하고 있습니다. 가장 큰 의미는 요소가 다른 모든 요소보다 큽니다. 동일한 요소가 없습니다. 그것이 전부입니다. 이것이 명확하지 않습니까?
James Wierzba 1

2
A, B, C, D를 사용한 마지막 예는 OP에 포함 된 경우 질문을 이해하는 데 도움이됩니다.
fade2black

3
C # 컴파일러 팀의 구성원이 인터뷰 질문으로이 질문을했습니다. C #에서는 과부하 해결 알고리즘 이 일반적이지만 반드시 전이적인 것은 아니지만 "더 나은"관계가 부여 된 경우 집합고유 한 최상의 멤버를 선택해야하기 때문에 관련 이 있습니다. (또는 독창적 인 최고의 회원이 없으면 적절한 답변을 제공하십시오. 유대가 가능합니다.) 정답에 답변했지만, "aha"통찰력에 의존하기 때문에 특히 좋은 인터뷰 질문이라고 생각하지 않았습니다. 선형 알고리즘.
Eric Lippert

답변:


38

최대 값을 찾기위한 표준 알고리즘이 여전히 작동합니다. 로 시작 당신이 더 큰 값을 참조하는 경우, 요소를 가서, 그 값으로 최대 값을 업데이트합니다. 이것이 작동하는 이유는 건너 뛴 모든 요소가 하나 이상의 요소보다 작기 때문에 최대 값이 될 수 없기 때문입니다.a1

명확하게 말하면, "표준 알고리즘"은 다음을 의미합니다.

max <- a_1
for i=2 to n
   if a_i > max
      max <- a_i
output max

완성도를 높이기 위해 의견에서 제기 된 문제에 대해 논의하겠습니다. 위의 논의에서의 설정은 안티 대칭 관계에 최대 상대 찾는 , 내가 모든 경우 최대 인 J 나는 우리가 난을<aiji . 위의 알고리즘은 최대 값이 존재한다는 가정하에 작동하지만 이것이 알려지지 않은 경우 최대 값의 존재를 확인하는 데 사용할 수 있습니다 (반환 된 요소가 다른 모든 요소보다 실제로 큰지 확인하십시오. 이는 Chi의 의견에 언급되어 있음) Ilmari Karonen에서 답변).ai>aj

경우 반드시 안티 대칭되지 않습니다 (에밀이 코멘트에 언급 한 바와 같이), 다음 위의 알고리즘은 실패합니다. 경우 < 임의의 관계 (즉, 우리가 이행 성 및 안티 대칭 모두 편안한있다), 선형 시간에 최대를 찾는 것은 불가능하다는 것을 보여 어렵지 않다. 넣어야 # 내가 횟수 내가 쿼리에 참가, 우리는 최대가 충분히 쿼리없이 공개 할 수없는 방식으로 적대 관계를 정의합니다. 쿼리 i > ? a j 이면 a i > a j 라면 # a i<<#aiaiai>?ajai>aj이면 최대 값이 아직 표시되지 않았으며 세트의 요소 중 하나로 설정 될 수 있습니다.#에이나는<1I < J 그렇지. 쿼리 수가 o ( n 2 ) 인 경우에이나는<에이j영형(2)


1
@JamesWierzba (제 생각에) 그는 "건너 뛴"요소가 현재 최대 값보다 크지 않다는 것을 의미합니다. 표준 알고리즘을 고려하십시오. 현재 최대 값과 비교하여 목록의 각 값을 확인하십시오. 각 목록에 가장 큰 요소가 있다고 말했습니다. 어떤 시점에서는 현재 최대 값과 비교하여 더 큰 값이 새로운 최대 값이됩니다. 이 값이 목록의 다른 모든 값보다 크기 때문에 더 큰 요소를 찾을 수 없으며 가장 큰 값이 대체되지 않습니다. n비교 후 , 당신의 현재 최대 값은 답이되어야합니다
Lord Farquaad

1
명확성을 위해 편집 된이 알고리즘은 전이성을 가정하지 않습니다. 믿기 ​​어려운 것을 발견하면 정확성 증명의 세부 사항을 따르십시오 (반환 목적으로 반환 값이 최대가 아니라고 가정하고 첫 번째 단락의 아이디어를 사용하십시오).
Ariel

7
이것은 문제의 가정 2에 의존합니다. 배열에는 항상 최대 값이 있습니다. 그렇지 않은 경우 max하위 배열의 최대 값 만 될 수 있습니다. 그럼에도 불구하고 가정 2가 없더라도 잠정 최대 값을 찾은 다음 O (n) 범위 내에서 두 번째 스캔을 사용하여 전체 배열에서이를 확인할 수 있습니다.

7
이 답변은 B > A 가 동시에 유지할 수 없다고 가정합니다 . 내가 볼 수있는 한, 이것은 질문에서 배제되지 않습니다. A>BB>A
Emil Jeřábek는 Monica를 지원합니다 :

4
@ oconnor0 다음과 같습니다. 구체적인 예를 들어 A> B, A> C, B> A 및 C> B로 가정합니다. 그러면 A가 세트의 다른 요소보다 크고 (이 특성을 가진 유일한 요소) 요소가 순서 (A)에 발생하는, B는 C, 알고리즘가 출력 C.
에밀 예라 벡 모니카 지원

24

아리엘이 지적한대로 표준 최대 찾기 알고리즘은 다음과 같습니다.

def find_maximum(a):
    m = a[0]
    for x in a:
        if x > m: m = x
    return m

실제로 다음과 같은 한 수정없이 작동합니다.

  • 모든 요소 쌍을 비교할 수 있으며
  • 입력은 최대 요소, 즉 입력의 다른 요소보다 쌍으로 큰 요소를 포함하도록 보장됩니다.

(최대 요소가 다른 모든 요소와 비교 가능 x > y하고 요소 xy비교할 수없는 경우 항상 거짓 이라고 가정하는 한 알고리즘을 수정하지 않아도 위의 첫 번째 가정은 실제로 완화 될 수 있습니다.)

특히 귀하의 주장은 다음과 같습니다.

[…] 답을 확실히하기 위해, 요소는 다른 모든 요소와 명시 적으로 비교되어야합니다 (비교가 전 이적이지 않기 때문에).

위에 주어진 가정에서는 사실이 아닙니다. 실제로 위의 알고리즘이 항상 최대 요소를 찾는다는 것을 증명하려면 다음 사항을 관찰하면 충분합니다.

  1. 루프는 모든 입력 요소를 반복하기 때문에 일부 반복 x에서는 최대 요소가됩니다.
  2. 최대 요소는 다른 모든 요소보다 페어 단위로 크기 때문에 반복이 끝날 m때 최대 요소가됩니다. 과
  3. 다른 요소는 최대 요소보다 페어 단위로 클 수 없으므로 m후속 반복에서 변경되지 않습니다.

따라서 m입력이 하나를 포함하는 경우 루프 끝에서 항상 최대 요소가됩니다.


추신. 입력에 항상 최대 요소가 포함되어 있지 않은 경우 사실을 확인하려면 실제로 다른 모든 요소에 대해 후보 응답을 테스트하여 입력이 실제로 최대인지 확인해야합니다. 그러나 위의 최대 찾기 알고리즘을 실행 한 후에도 O ( n ) 시간 에이를 수행 할 수 있습니다 .

def find_maximum_if_any(a):
    # step 1: find the maximum, if one exists
    m = a[0]
    for x in a:
        if x > m: m = x

    # step 2: verify that the element we found is indeed maximal
    for x in a:
        if x > m: return None  # the input contains no maximal element
    return m  # yes, m is a maximal element

(여기서는 관계 >가 비 반사적 이라고 가정합니다 . 즉, 요소가 자신보다 클 수는 없습니다. 반드시 그렇지 않은 경우 x > m2 단계 의 비교 를x ≠ m and x > m . 여기서, ID 비교를 나타냅니다. 또는 최적화를 적용 할 수 있습니다. 아래에 명시되어 있습니다.)

이 알고리즘 변형의 정확성을 입증하려면 두 가지 가능한 경우를 고려하십시오.

  • 입력에 최대 요소가 포함되어 있으면 1 단계에서 위와 같이 찾은 다음 2 단계에서이를 확인합니다.
  • 입력 에 최대 요소가 포함되어 있지 않으면 1 단계에서 임의의 요소를로 선택 m합니다. 어떤 경우에도 최대가 아니므로 2 단계에서이를 감지하여 리턴 None합니다.

m입력 배열에 인덱스를 저장하면 나중에 2 단계에서 이미 요소가 비교되었으므로 a이전 m에 오는 요소 만 확인하도록 실제로 2 단계를 최적화 할 수 a있습니다 m. 그러나이 최적화는 점근 시간 복잡성을 변경하지 않습니다. 알고리즘은 여전히 ​​O ( n )입니다.


3
실제로 OP는 많은 세부 정보를 건너 뜁니다. 예를 들어, 관계의 반사성에 대해서는 아무 것도 언급되어 있지 않으므로 반사적이지 않으면 if x > m:정의되지 않습니다.
fade2black

4

"가장 큰 것은 요소가 다른 모든 요소보다 커야 함을 의미합니다"는 O ( n ) 에서이를 수행하는 방법에 대한 큰 힌트입니다.O(n) .

요소를 비교하는 목록을 살펴보면, 비교를 "손실"하는 요소는 다른 요소보다 커야 단일 손실이 실격되기 때문에 즉시 모든 요소를 ​​버릴 수 있습니다.

그런 식으로 생각하면 실제로 n - 1을 만들 수 있음이 분명합니다.n1 하면, 매번 패자를 버림으로써 비교를하고 마지막 비교 결과로 가장 큰 요소로 끝날 .

이 솔루션은 항상 가장 큰 요소가 있다는 사실과 결합 된 "어떤 요소도 같을 수 없습니다"라는 미묘함에 의해 가능합니다. 우리가지도 관계를 유 방향 그래프로 매핑한다면, 단순히 승리를 따름으로써 가장 큰 요소에 도달 할 수 있다는 것이 분명합니다.


1
" 비순환 지향 그래프 "는 잘못된 모델입니다. 대신 " 토너먼트 " 여야합니다 . 사이클이 허용되며 모든 모서리가 정확히 한 방향으로 존재하는 것이 중요합니다.
피터 테일러

@PeterTaylor 당신은 절대적으로 옳습니다. 나는 '가장 큰'요소를 이끌어내는 승리에 대해서만 생각하고 있었지만 다른 승리는 관련성이 적지 만 가장 큰 것을 발견하는 길을 통과 할 수 있으므로 당신이 할 수있는 것이 맞습니다. ' t 할인
Danikov

3

나는 적어도 하나의 요소에 대한 비대칭 관계 (가장 큰 요소의 존재를 보장하는)를 가정합니다. 그렇지 않으면 작업이 불가능합니다. 유한 세트의 모든 요소가 비교 가능한 경우 일반적인 찾기 최대 절차가 작동합니다.

일부 요소가 비교 가능하지 않으면 다음 절차가 작동합니다.

max = nil
For i=1 to n
   if max is nil then
      max = a[i]
   if max and a[i] are not comparable then
      max = nil
   else if max < a[i] then
      max = a[i]
End

이것이 알고리즘이 입력에서 작동하는 방식입니다 에이,,기음,

에이>,>기음,기음>에이
>에이,>,>기음
귀하의 게시물에서와 같이.

처음에. 최대 = nil
나는=1: max=A
i=2: max=A (since A>B)
i=3: max=C (since A<C)
i=4: max=D (since D>C)

This algorithm works since if m>a (or a<m) for all a then m is the greatest. If m<a for some element a then m cannot be the greatest. Similarly, if a and m are not comparable then they both cannot be the greatest. This procedure would work even if all elements are comparable.


I don't think the first else if is needed. It cannit be triggered if max is the maximum, and if the maximum has not yet been encountered it doesn't matter what the value of max is.
rici

Yes, that is the first one. The other one is the second one :)
rici

You mean leave ifs without elses? It is just a habit: with elses we do not even compare. :)
fade2black

1
Wouldn't it be simpler to just initialize max to any element of the list and, inside the loop, do if max and a[i] are comparable and max < a[i] then max = a[i] (where the first part of the condition could be omitted if we assume that trying to compare two incomparable elements always yields false)?
Ilmari Karonen

1
@badallen the OP assumes that there is always the greatest element. In your example there is no greatest element.
fade2black

2

As an addition to Ariel's answer about the concerns raised by Emil Jeřábek: If we allow A<B and B<A then there is no O(n) algorithm:

Assume you have elements A1...An. Your algorithm will in each step query Ai<Aj for some pair i and j. No matter in which order you query them, there is always a relation where you have to query all relations before finding the maximum. The reason for this is best described by assuming you have an adversary who can change the problem while your algorithm is running.

(Note that the argument is independent of what the algorithm actually does with the information he gets about the elements, since it explains that he cannot know that an element is maximal before making n2 queries.)

For most of the algorithm the adversary will make sure to always return true for Ai<Aj until your last query for a given j. Note that you cannot know that one given element is maximal until you compared it to all other elements. Only for the last element for which you finish all relations the adversary will return true for the last element as well.

The resulting relation will always be such that there is some j0 for which Ai<Aj0i and for all other j there will be some ij such that Ai<Ajiij and we will not have Aij<Aj. The adversary chooses j0 and the ijs depending on your algorithm.

I hope this is somewhat understandable. Feel free to ask in comments or edit.

The basic idea is that you cannot gather any information about the remaining elements from the ones you already know if you allow a completely arbitrary relation.

The argument still works if we disallow A<A. We will only save n queries that way and still need n2n.


1

I'm going to cheat and call the number of A > B entries n and you need to look at every entry at least once.

That way you can loop over just the entries and remove the element that is less than the other from the set of possible solutions. With a hashset or similar this is possible in O(n)

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