in O(n)time:比較が推移的でないセット内で最大の要素を見つける


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>A
fade2black

6
少なくとも部分的に順序付けされていないセット内の最大の要素をどのように選択するか想像できません。最大要素と最小要素の定義をご覧ください。推移性の欠如は半順序を排除します。
fade2black

3
@ fade2black「最高」の別の定義にリンクしているのはなぜですか。私はこの質問の文脈で最大の定義を明示的に述べています。最大の意味は、要素が他のすべての要素よりも大きいことです。等しい要素はありません。これですべてです。これは明らかではありませんか?
ジェームズWierzba

2
A、B、C、Dの最後の例は、OPに含めた場合の質問を理解するのに役立ちます。
fade2black

3
C#コンパイラチームのメンバーは、これをインタビューの質問として使用していました。C#では、オーバーロード解決アルゴリズムは、通常ではあるが必ずしも推移的ではない「ベターネス」リレーションが与えられたセットの一意の最適なメンバーを選択する必要があるため、関連性があります。(または、そのようなユニークな最高のメンバーがいない場合は適切な応答を提供します。関係は可能です。)私はそれを正しく答えることはできましたが、線形アルゴリズム。
エリックリッパー

回答:


38

最大値を見つけるための標準アルゴリズムは引き続き機能します。始まる1、あなたは大きな値を見れば、要素の上に移動し、その値に最大値を更新します。これが機能する理由は、スキップしたすべての要素が少なくとも1つの要素よりも小さいため、最大にすることができないためです。a1

明確にするために、「標準アルゴリズム」とは、次のことを意味します。

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

完全を期すために、コメントで提起された問題をここで説明します。上記の議論の設定は、すべてのj iに対してa i > a jが存在する場合にa iが最大となる、反対称関係に対する最大値を見つけることです。上記のアルゴリズムは、最大値が存在するという仮定の下で機能しますが、これが不明な場合は、最大値の存在を確認するために使用できます(返される要素が実際に他のすべての要素よりも大きいかどうかを確認し、これはChiのコメントに記載されていますイルマリ・カロネンの回答)。<aijiai>aj

が必ずしも反対称ではない場合、上記のアルゴリズムは失敗します(Emilがコメントで述べたように)。<が任意の関係である場合(つまり、推移性と反対称性の両方を緩和している場合)、線形時間で最大値を見つけることが不可能であることを示すことは難しくありません。表す回数iのクエリに参加したが、我々は最高の十分なクエリなしに明らかにすることができないという方法で、敵対関係を定義します。クエリa i > jは、答える > jの場合は私を<<#aiaiai>?ajai>ajそれ以外の場合 < n 1および a i < a j。クエリの数が o n 2)の場合、最大値はまだ見られず、セット内の要素のいずれかに設定できます。#ai<n1ai<ajo(n2)


1
@JamesWierzba(私は思う)彼は単に「スキップされた」要素があなたの現在の最大より大きくないものであることを意味します。標準アルゴリズムを検討してください。リストの各値を現在の最大値と照合します。各リストには最も大きな要素があるとおっしゃいました。ある時点で、それを現在の最大値と比較し、それが大きいため、その値が新しい最大値になります。この値はリスト内の他のすべての値よりも大きいため、大きい要素を見つけることはできず、最大値は置き換えられません。あなたの後nの比較、あなたの現在の最大値は、答えなければならない
主Farquaad

1
明確にするために編集されたこのアルゴリズムは、推移性を想定していません。信じがたいと思う場合は、正しさの証明の詳細に従ってください(矛盾するために、戻り値が最大値ではないと仮定し、最初の段落のアイデアを使用してください)。
アリエル

7
これは、質問の仮定2に依存しています。配列には常に最大値があります。これが当てはまらない場合maxは、サブアレイの最大値になる可能性があります。それでも、仮定2がなくても、暫定的な最大値を見つけてから、O(n)境界内で2回目のスキャンを使用して配列全体で検証できます。
チー

7
この答えは、B > Aを同時に保持できないことを前提としています。私が見る限り、これは質問で除外されていません。A>BB>A
エミールイェジャベクはモニカをサポートします

4
@ oconnor0それは続きません。具体的な例として、A> B、A> C、B> A、C> Bと仮定します。その後、Aはセット内の他のどの要素よりも大きい(そしてこのプロパティを持つ唯一の要素)が、要素がオーダーA、B、C、アルゴリズムの意志出力C.で遭遇
エミルJeřábekはモニカサポート

24

Arielが指摘しているように、以下に示す標準の最大検出アルゴリズム:

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 > mステップ2 の比較をに置き換えます。x ≠ m and x > mここで、同一性比較を示します。以下に記載されています。)

アルゴリズムのこのバリエーションの正確性を証明するために、考えられる2つのケースを検討してください。

  • 入力に最大要素が含まれている場合、ステップ1でそれが検出され(上記を参照)、ステップ2で確認されます。
  • 入力に最大要素が含まれていない場合、ステップ1は任意の要素をとして選択しmます。どの要素でも最大ではないため、どの要素であるかは関係ありませんNone。したがって、ステップ2はそれを検出してを返します。

のインデックスをm入力配列に保存した場合a、実際にはステップ2を最適化mしてa、前に来る要素のみをチェックできmます。これは、後の要素が既にステップ1 と比較されているためです。アルゴリズムの、まだO(n)です。


3
実際、OPは多くの詳細をスキップします。たとえば、関係の再帰性については何も言われていないため、再帰性がない場合if x > m:は未定義です。
fade2black

4

「最大は、要素が他のすべての要素よりも大きくなければならないことを意味します」は、です。O(n)

リストを比較して要素を比較すると、比較を「失う」要素はすぐに破棄されます。最大のものになるには、他のすべての要素よりも大きくなければならないため、単一の損失で失格になります。

そのように考えると、実際にnを作成できることは明らかです。n1

このソリューションは、「最高の要素は常に存在する」という事実と組み合わされた「要素を等しくすることはできません」という微妙な点によって可能になります。勝ち関係を有向グラフとしてマッピングすると、勝ちをたどるだけで最大の要素に到達できることは明らかです。


1
非周期的な有向グラフ」は間違ったモデルです。代わりに「トーナメント」である必要があります。サイクルは許可されており、すべてのエッジが正確に一方向に存在することが重要です。
ピーターテイラー

@PeterTaylorあなたは絶対に正しいです、私は「最大」の要素につながる勝利についてだけ考えていました、他の勝利はあまり関連性がありませんが、あなたが彼らができることを正しいので、最高を発見する道をたどる可能性があります」割引される
Danikov

3

I assume that the relation antisymmetric for at least a single element (which guarantees the existence of the greatest element), otherwise the task is impossible. If all elements in the finite set are comparable then usual finding-maximum procedure works.

一部の要素が比較可能でない場合、次の手順が機能します

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

これは、アルゴリズムが入力に対してどのように機能するかです ABCD

A>BB>CC>A
D>A,D>B,D>C
as in your post.

Initially. max = nil
i=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.