VIDTAKER.COM

Q&A

それが正確にN / 2回表示される番号を探す


こんにちはすべて、

ここは私の面接の質問です。各素子のN配列を渡すと場所の要素が独自の表示が正確にN / 2回 / 2つの要素をはN残り。どのように改善の実行時間を持つ要素を見つけるか?

要素を覚えておいては、ソートされて、あなたは、Nを取ることもです。たとえば、

input array [] = { 10, 2, 3, 10, 1, 4, 10, 5, 10, 10 }

だからここ10が表示されますN / 2のですextactly 5回。

私は)ランタイムはO(nで解決策を知っている。しかし、まだ転送はO(log n)のよりよい解決策を知っている。



14 Replies

1)

あなたは、エラーの小さな確率を受け入れる準備ができている場合は一定の時間のソリューションです。ランダムサンプルでは、配列から2つの値、それらが同じである場合、あなたが探している値を発見した。各ステップで、あなたは仕上げていないの0.75の確率があります。そして、すべてのイプシロンのための、そのような(3 / 4)^ nの<epsファイルは、我々ができるサンプル最大n個の時のnが存在するとエラーを返す私たちが一致するペアを発見していない場合。

我々はペアを予想実行時間を見つけるまでサンプリングを続けると、一定であるまた、発言が、最悪の場合には時間が実行されて有界ではない。


2)

ここでは、これは以下で行うことができない理由の証明に私の試みは、O(nより)確かにこの例では唯一の興味深い例である場合には、最悪の事態に配列アクセス():

)アルゴリズムを最悪の場合をlog(n仮定が存在します。最大でこのアルゴリズムのアクセス配列のログ(n)回。それは仮定の要素がここで、私は選択を聞かせているどの行うことができますので、どのログ(n)はそれが見ている要素。私はそれを最初のログ(n)の一意の要素を与えるように選択されます。それはまだ重複し、見つかったていない、まだがn / 2が存在する - (n)は、それを養うために私のための一意の要素を記録する場合は、必要があります。それは/ 2つの要素をnを読むまで実際には、私は重複数を、それを餌に強制することはできません。したがって、このようなアルゴリズムが存在することはできません。

純粋に直感的な観点から、これは不可能だ。ログは、(4億円)32です。だから40億の数字、2億が独自のは、順不同で、方法があるのはわずか32の要素をチェックして重複要素を見つけることですの配列?


3)

配列を読む必要があるので、サブリニアスペース時間でこれを行うことはできません。対数時間で100万レコードの配列を処理するだけで〜20(log2)の要素を - 明らかに不可能読んで必要だ。すべての後に想定した場合、最初に500001の要素を見て重複を見つける必要がありますので、Nは/ 2回はまだはO(nだ)が繰り返されますが重複しています

あなたは、整数を取る場合はO(n)でこの作業を行うことができます非負ています。それは次のように行くこの(擬似のJava):

int repeatedNumber = -1; // sentinel value
int count = 0;
BitSet bits = new BigSet(); // this bitset needs to have 2^31 bits, roughly 2.1 billion
boolean duplicate = false;
for (int i : elements) {
  if (bits[i].isSet()) {
    if (repeatedNumber == -1) {
      repeatedNumber = i;
      count = 1;
    } else if (i == repeatedNumber) {
      count++;
    } else {
      System.out.println("Array has more than one repeated element");
      duplicate = true;
      break;
    }
  } else {
    bits[i].set();
  }
}
if (!duplicate && repeatedNumber != -1 && count == elements.length/2) {
  System.out.println(repeatedNumber + " occurred " + count + " times. The rest of the elements are unique");
} else {
  System.out.println("Not true");
}

同様の方法はO一意の整数(n)は(基数ソート)の配列をソートするために使用されます。


4)

ケースでは最悪の決定的な動作は、はO(N))が正しい(前の私は1つ以上の証明書をよりてすでに見た回答。

しかし、現代のアルゴリズム理論はなぜほかほかの多くの大代areだ最悪の動作(だけで心配していない大Oのにもかかわらず、急いでしばしば大きな- Oを使用してin怠惰なプログラマーでもいつ何を彼らが考えている大オメガ;-)または大シータに近い、また、決定だけで(withnessミラー - ラビン素数判定法...;).です

のK <N項目の任意のランダムなサンプルでは、probabllityとは重複して表示されますが<2 **のK - 簡単かつ迅速に本質的に、あなたはどのようなNは(あなたは確率未満に減らすことができるなどの問題を希望低減少ランダム宇宙線は;-)れる誤って、メモリでビットをundetectablyフリップ-この観測はほとんど;-)を必要とする創造性ラビンアプローチテスト首相ミラーが必要を見つけるの確率。

これはかなりお粗末なインタビューの質問になるだろう。類似度の低いお粗末な質問は、と答えたしばしば提起は、しばしばミスしばしば誤って候補失敗記憶します。たとえば、典型的な質問かもしれない、(のO、指定された配列であるN個の項目がではなく、知っているかどうか1つがそこにあると多数の項目を決定するかどうかですが、1個のN)時間とO(1)補助スペースは(そうするだけで)ハッシュテーブルか何か別の値の出現回数を数えるように設定することはできません。 "ムーアの投票のアプローチ"(良い解決策はおそらく質問最高の1つのインタビュー)にその価値がある

もう一つの興味深いバリエーション:何がある場合10**18 64ビットの番号は(データ全体の8テラバイト分のBigTableのまたはそのクローン)、また多くのマシンとしては、それぞれかなりの高速無線LANについて4GBのRAMの上に言って欲しいように言う実質よりもGBのイーサネットの1つどうやっ-あなたの条件の下でこれらの問題をシャード?何がある場合は/ HadoopのMapReduceを使うには?何がこの1つの問題のためだけに自分専用のフレームワークを自由にデザインしている場合 - あなたはMapReduceより良い性能を得ることができる?どのくらい良いの粒度でバックエンベロープ推定の?私はこのバリアントは公開されてアルゴリズムを知って、それは偉大なテストあなたはテラスケール計算に高度に分散アプローチでの候補者の一般的な施設をチェックする場合がありますので、...


5)

私はあなたが単純に配列2つの要素のバックログを維持を通じて解析する必要がありますね。 N / 2のように等しく、残りの部分が異なることが保証さですが、1つの場所私はあなたの配列にする必要があります場所

a[i] == a[i-1] OR a[i] == a[i-2]

あなたの配列を反復処理1回で、あなたの複雑さを持って約2 * NにするだけでなくはO(N)内にあります。

この回答はややガネーシュMとドギーで答えに似ていますが、私は少し簡単だと思う。


6)

私の回答は、さ

  1. 3つの要素を持ってで[n / 3]の部分(すなわち)の各部分にN個の要素を分割します。
  2. 今、お互いの間で、これらの3つの要素を比較する。 - 3比較検討
  3. 少なくとも1つの製品の同じ要素の2つのコピーになります。したがって、数。

ランタイム - (N)はOの


7)

はO(n未満)より、すべての番号を読み取ることはしなければならない、それを行うために。
あなたはその後、可能性が単なるサンプルの小さなサブセットを見ることは1つだけの数の関係を満たすために十分な時間が表示されます関係をsatisifies値が知っている。一様に分布する値を仮定する必要があります合理的です

編集します。あなたがそのような番号が存在していたことを証明にn / 2を読むには、しかし、もしあなたの番号を知っているだろうと存在だけを検索したい - あなたはSQRTは(n)のサンプル読むことができる


8)

ピーターはまったく正しいです。ここに彼の証明を再確認のより正式な方法があります:

セットには、N個の要素を含んでいるSを設定しましょう。それが繰り返されるの2つの労働組合であるセット:pとαを含むシンボルをN / 2回、とq、2を含むN / 2のユニークなシンボルω1 ..ωn /。のS =は、p∪qと

2と仮定>すべてのNがの場合最悪の比較 )アルゴリズムnのログ(数をすることができます検出の重複。場合には最悪のrを意味するのα場所2 Nをそこにはない存在するすべてのサブセットをrを⊂ログ= rの|はSように|。

∪qはしかしためのS = pのがなければなりませんれ| p |多くの要素≠/αで米| p | = N 2のため、∀N / 2のように、N / 2≥ログにNを、そこにrをとNα∉存在少なくとも1つのセットをrを⊂S 2のログインよう| rを| =これは、いかなるN≥3の場合です。そこにこのようなアルゴリズムすることはできませんので、これは、仮定上矛盾する。

QEDの。




9)

私が正しく問題を理解している場合:すべての我々は配列知っているそれは長さだが、それは(1要素は、N / 2回(特定の順序で繰り返しであるN / 2)+1ユニークな要素)があります。

私はあなたが本当に主張することはできませんこのソリューションの(一般的な配列のO(N)のハードリミットを受ける)が同じ数の少なくとも2を見つけること番号を見つけたと思います。私はそこにはO(入力サイズの重複を検出することができます順序配列の検索が存在すると思う)(dontは私が間違っている場合、私を修正してください)。あなたはいつも最悪の場合、少なくともN / 2の1の要素を読み取るために必要になります。


10)

あなたはこのようなPythonのアルゴリズムがあると:

import math
import random

def find_duplicate(arr, gap):
    cost, reps = 0, 0
    while True:
        indexes = sorted((random.randint(0,len(arr)-i-1) for i in xrange(gap)), reverse=True)
        selection = [arr.pop(i) for i in indexes]
        selection_set = set(selection)
        cost += len(selection)
        reps += 1
        if len(selection) > len(selection_set):
            return cost, reps

アイデアはarrがいるそのギャップセットあなたのは価値観とされるログベース2サイズ。 ギャップ要素それぞれ選択時には、参照してください値です重複がある場合。もしそうなら、)と反復回数(あなたが)繰り返しあたりの要素をlog2(サイズを調べる)の要素を検討のカウントでコスト(返します。サイズセットギャップそれ以外の場合、顔で別の。

このアルゴリズムをベンチマークの問題は、データの作成は、ループやデータの改ざんを通るたびに、高価と仮定している大量のデータ。 (当初、私は10 000 000反復1 000 000要素をしていた。)

それでは、同等の問題を減らすことができます。データはとしてn / 2のユニークな要素であり、n / 2を繰り返し要素に渡されます。アルゴリズムが)要素をチェック重複log2(nのランダムなインデックスを選択する。今我々が検討要素を行う削除作成にも持っていないとデータを:以上のポイント半インデックスを我々はもっと我々は2つの場合、またはことができるだけご確認ください。選択してギャップインデックスは、戻り値:チェック2度以上の中間点が見つかった場合は、それ以外の場合を繰り返します。

import math
import random

def find_duplicate(total, half, gap):
    cost, reps = 0, 0
    while True:
        indexes = [random.randint(0,total-i-1) for i in range(gap)]
        cost += gap
        reps += 1
        above_half = [i for i in indexes if i >= half]
        if len(above_half) >= 2:
            return cost, reps
        else:
            total -= len(indexes)
            half -= (len(indexes) - len(above_half))

今、このようなコードをドライブ:

if __name__ == '__main__':
    import sys
    import collections
    import datetime
    for total in [2**i for i in range(5, 21)]:
        half = total // 2
        gap = int(math.ceil(math.log10(total) / math.log10(2)))
        d = collections.defaultdict(int)
        total_cost, total_reps = 0, 1000*1000*10
        s = datetime.datetime.now()
        for _ in xrange(total_reps):
            cost, reps = find_duplicate(total, half, gap)
            d[reps] += 1
            total_cost += cost
        e = datetime.datetime.now()
        print "Elapsed: ", (e - s)
        print "%d elements" % total
        print "block size %d (log of # elements)" % gap
        for k in sorted(d.keys()):
            print k, d[k]
        average_cost = float(total_cost) / float(total_reps)
        average_logs = average_cost / gap
        print "Total cost: ", total_cost
        print "Average cost in accesses: %f" % average_cost
        print "Average cost in logs: %f" % average_logs
        print

youは、このテストをしようとすると、あなたは、時代の数は、アルゴリズムがdata内の要素の数with複数選択の低下を行うにはいる見つける。それはログ平均コスト、漸近的に1に近づく

elements    accesses    log-accesses
32          6.362279    1.272456
64          6.858437    1.143073
128         7.524225    1.074889
256         8.317139    1.039642
512         9.189112    1.021012
1024        10.112867   1.011287
2048        11.066819   1.006075
4096        12.038827   1.003236
8192        13.022343   1.001719
16384       14.013163   1.000940
32768       15.007320   1.000488
65536       16.004213   1.000263
131072      17.002441   1.000144
262144      18.001348   1.000075
524288      19.000775   1.000041
1048576     20.000428   1.000021

今では、 大文字のnに最適(アルゴリズムれてlog2平均引数この?おそらく。それは確かにそう、最悪の場合ではない。

また、)一度に要素をlog2(nを選択する必要はありません。あなたは2を選択することができますと平等のチェック(ただし、ケースを縮退の場合は、で重複をすべて)、またはより大きい複製の他の番号を確認見つけることができません。彼らが選択how多くは、どのように彼らは重複をidentifyこの時点で、すべてのアルゴリズムは、この中でのみ変化がselect要素と重複チェックは同一。


11)

あなたは、その要素は、あなたが探していると言われている場合、非ユニークな確かに最も簡単な方法は2つのと同じとし、その要素を返すと見ることをやめるが見つかるまで配列に沿って処理することですです。であなたの半分の配列を検索する必要がほとんど。

私はこのはO(n)であるので、私はそれは本当に問題が解決しないと思いますね。

それはあまりに私が正しく問題を理解していないと思う単純なようだ。


12)

ので、私はフォーマットできコメントからガネーシュのバージョンに私の解決策を再確認:

for (i=0; i<N-2; i+=3) { 
   if a[i] == a[1+1] || a[i] == a[i+2] return a[i];
   if a[i+1] == a[i+2] return a[i+1]; 
} 
return a[N-1]; // for very small N

勝利の確率1反復:50%後

勝利の確率2反復:75%後

最悪の場合は、O(n)の時間はO(1)スペース。

このループはそれがいる場合以上の3 / 4の配列として指定を反復処理することはありませんので、N個/ 4反復した後、すべてのN / 2一意の番号を使って注意してください。


13)

まず、それは私のベッドの時間を過ぎて、私はより公共の場で初めて、矢田は、矢田、それをしようとせずにコードを作成する知っている必要があります。私は、少なくとも教育されるのかよ批判を願っています。 :-)

私は問題のように修正再表示できると信じて:"2回以上発生する番号を探します。"

絶対最悪の場合、私たちは少しの半分以上リスト(反復処理する必要があります1 + N / 2の)我々は、非一意の番号の第2のインスタンスを見つける前。

最悪の場合の例:配列[] =(1、2、3、4、5、10、10、10、10、10)

平均数も、他の我々はすべての約すなわち数が3または4を反復処理する必要がありますね唯一のユニークな子要素が含まれている以外の要素は、以降の半分。

完全に均等に分布の例:

  • 配列a [] =(1、10、2、10、3、10、4、10、5、10)
  • 配列a [] =(10、1、10、2、10、3、10、4、10、5)

言い換えれば、他の場合でも、はN = 1000000を検索することもする必要がありますのみ、平均で、最初の3または4つの要素が重複して前に発見した。

何がNしない増やす固定/定数ランタイムだの表記大台に乗る?

コード:

int foundAt = -1;

for (int i=0; (i<N) && (foundAt==-1); i++)
{
    for (int j=i+1; j<N; j++)
    {
        if (array[i] == array[j])
        {
             foundAt = i;
             break;
        }
     }
}

int uniqueNumber = array[foundAt];

14)

これは、貧しい人々のインタビューの質問です。

  1. あなたは答えを自分でわからない。
  2. それは背後にあるビジネスケースを持っていない場合は、難易度を候補に説明しているようにします。

曇り最初の1つのために。何を探してるんですか?その候補者は、このO(log n)のソリューションではわからないとまで来る必要があります存在するか?あなたはStackOverflowを求めるには、持っている場合は、合理的に候補者を期待できるこの何かのインタビューで思い付くのですか?