32ビットアーキテクチャで可能なすべての数値を含むファイルが提供されます。そのファイルには4つの数字がありません。欠落している4つの数字を見つける


22

これはインタビューの質問で、何度か出くわしました。4つの数字が欠けているので、どうやってそれを解決するのかわかりません。私は1つまたは2つの数値が見つからないことを見つけるためのアルゴリズムに精通していますが、それらのいずれかを4に一般化する方法がわかりません。


回答:


19

インタビューであろうと実際の仕事であろうと、あなたにとって一番の優先事項はあなたにとって意味のある実用的なソリューションである必要があります。これは通常、あなたは、シンプルで使いやすいためであることを考えることができ、第一の溶液を提供する必要があることを意味しますが、説明することを。

私にとって、それは数字を並べ替え、ギャップをスキャンすることを意味します。しかし、私はビジネスシステムとWebアプリに取り組んでいます。私は少しもいじりませんし、私のチームにもしたくありません!

低レベルの、より金属に近い仕事のためにインタビューしている場合、「ソート」はおそらく空白の視線で満たされます。彼らはあなたにあなたがビットなどについて快適に考えることを望んでいます。最初の答えは、「ああ、ビットマップを使用します」です。(またはビット配列、またはビットセット。)

そして、どちらにしても、「間違った」解決策を与えたとしても、インタビュアー(または上司!)がそれを求めた場合、マネージャーの特定の関心領域に焦点を合わせて、いくつかの改善または代替案を提案できます。

  • RAMが大幅に制限されていますか?512MB未満ですか?
    ディスク上の所定の場所に並べ替えます。ほとんど任意の量のRAMを使用して、ソートされたブロックを最適化またはバッファリングできます。
  • 限られた時間?
    そのRAMを使用してください!並べ替えは既に行われていO(n*log(n))ます。(または整数バケットソートの場合はO(n)!)
  • 保守性?
    ソートよりも簡単なことは何ですか?!
  • ビットフラグ/フィールドの知識を実証しませんか?(BitSet/ BitMap/ BitArray
    まあOK ...先に進み、a BitArrayを使用して「見つかった数字」にフラグを立てます。次に、をスキャンし0ます。
  • 予測可能な「リアルタイム」の複雑さ?
    ビットマップソリューションを使用します。これは、ファイルに対する1回のパスとBitArray/に対する別のパスですBitSet0'sを見つけるため)。それだO(n)、私は思う!

または何でも。

実際に抱えている懸念に対処します必要に応じて素朴なソリューションを使用して、最初に問題を解決してください。まだ存在しない懸念に対処するために全員の時間を無駄にしないでください。


私は、ディスク上で言うまでもなく、単純なアプローチで40億個の数字をソートする可能性についてはよくわかりません。しかし、試したことはありません。
栄子

1
@Eikoえーと...繰り返しますが、要点は...物事を過度に複雑にしないでください。最初のステップは、単純な問題であっても、問題を解決するために考えられるあらゆる方法で解決することです。ビジネスが解決策を必要としているだけで、「適切な」ソリューションを確実に提供するために時間を費やしている場合、将来の雇用主が抱える不満のレベルを強調することさえできません。両方できることを証明してください!問題を迅速に解決できることを証明し、必要に応じてリファクタリングおよび/または最適化する価値のある潜在的な問題を特定します
svidgen

1
@Ewan「面接で質問が出てきたから」は、「すべてのマネージャーが探している特定の答えがある」と同じではありません。...問題を解決する能力を実証し、私があなたに決して与えなかった問題を解決することに巻き込まれない限り、あなたが私にどんな解決策を与えたかは確かに気にしないでしょう!
svidgen

1
ポイントがありません。この質問とそのバリエーションは、プログラミングパズルの本やインタビューの質問で発生します。それは質問をする人によって作られたものではありません。32ビットのものは、数字を追跡したりソートしたりすることで不可能になると考えられています。それが書かれてからちょうどそのコンピュータはより速く/より大きくなりました。
ユアン

1
@Ewan:質問のインスタンスにはOPと同じ制約があるとまだ仮定しています。OPは、アルゴリズムを32ビットマシンで実行する必要があるとは言いませんでした。コンピューターで実行する必要があるとも言っていませんでした。概念的なアルゴリズムが適しています。また、8ビットのマイクロコントローラーでも任意のサイズの整数演算が可能であるため、「すべての可能な数値」の意味を述べていません。絶対的な声明を出すためにあなたがしているかなり多くの仮定。
-whatsisname

19

ファイルであるため、複数のパスを作成できると想定しています。最初に256個のカウンターの配列を作成し、ファイルを反復処理し、数値ごとに、数値の最初のバイトとしてインデックス付けされたカウンターをインクリメントします。完了したら、ほとんどのカウンターは2 ^ 24になっているはずですが、1〜4個のカウンターの値はもっと小さいはずです。これらの各インデックスは、欠落している数値の1つの最初のバイトを表します(4未満の場合は、複数の欠落した数値が同じ最初のバイトを共有するためです)。

これらのインデックスごとに、256カウンターの別の配列を作成し、ファイルに2回目のパスを作成します。今回は、最初のバイトが以前の値の1つである場合、2番目のバイトに基づいて配列のカウンターをインクリメントします。完了したら、2 ^ 16未満のカウンタを再度検索すると、不足している数字の2番目のバイトがあり、それぞれが最初のバイトに一致します。

3番目のバイト(各バイトの後に最大4つの異なるバイトが続く場合でも、各パスで最大4つの配列が必要であることに注意してください)および4番目のバイトで、すべての不足している数字を見つけました。

時間の複雑さ- O(n * log n)
スペースの複雑さ- 一定

編集:

実際にはn=2^32、これがパラメーターであると考えましたが、欠落している数字の数k=4もパラメーターです。k<<nこれがスペースの複雑さを意味すると仮定しO(k)ます。

更新:

ちょうど楽しみのために(と私は現在、錆を学ぶためにしようとしているので)私は錆でそれを実装:https://gist.github.com/idanarye/90a925ebb2ea57de18f03f570f70ea1f。オンワンは〜2 ^ 32の数値で実行するため、テキスト表現を選択しました...


すべての数値をメモリに保持する(複数パスの場合)には、4バイト* 2 ^ 32メモリが必要です。したがって、すべてのI / Oを4回行う可能性が高くなります。しかし、使用される他のメモリは非常に小さいので、すばらしい仕事です。
user949300

1
@ user949300私は、このソリューションは作品によって、ファイルの断片を読み込むと仮定ではなく、一度にメモリに全部をロードしています
リチャード・チンクル

「ほとんどのカウンターは2 ^ 24である必要がありますが、1〜4個のカウンターはより低い値を持っている必要があります」-間違っています。次:2番目のパスでいくつの配列を作成しますか?256、1から4倍256、256倍256?そして、3番目と4番目のパスで?
ベルンハルトヒラー

3
@BernhardHillerこのファイルには、32ビット空間にすべての可能な数字が含まれ、4つの異なる数字を保存します。そのため、最初のバイトはすべて発生し、そのうちの1〜4個だけがヒット数が少なくなります。
ラッセV.カールセン

@ LasseV.Karlsenありがとう、アルゴリズムを理解しました。
ベルンハルトヒラー

6

これがJavaであれば、BitSetを使用できます。そのうちの2つは、32ビットの数値をすべて保持できないためです。骨格コード、おそらくバグあり:

BitSet bitsetForPositives = new Bitset(2^31);  // obviously not 2^31 but you get the idea
BitSet bitsetForNegatives = new Bitset(2^31);

for (int value: valuesTheyPassInSomehow) {
  if ((value & 0x80000000) == 0)
     bitsetForPositives.set(value );
  else
     bitsetForNegatives.set(value & ~0x80000000);
}

次に、BitSet.nextClearBit()行方不明者の検索に使用 します。

後で追加されたメモ:

このアルゴリズムを使用すると、時間のかかる部分を並行して実行するのはかなり簡単です。元のファイルが4つのほぼ等しい部分に分割されているとします。4組のBitSetを割り当てます(2GB、依然として管理可能)。

  1. 4つのスレッドを並行して使用し、それぞれが1つのファイルを処理して、独自のビットセットのペアにします。
  2. 完了したら、単一のスレッド、またはビットセット(ささいな時間)に戻り、nextClearBitを4回(これもささいな時間)呼び出します。

I / Oがレート制限のステップであると期待していますが、魔法のようにすべての数値がメモリ内にあれば、本当に速度を上げることができます。


3
@イダン・エア。このソリューションではコードがほとんど必要ないため、コーディングエラーの可能性が低くなります。私はこれが時間O(n)であることがかなりいいです。また、巨大なファイルの複数のパスを想定/必要としないため、複数のパスを必要とするアルゴリズムよりも使用するスペースが少なくなります。「ああ、愛しい」という意味を詳しく説明してください。
user949300

2
Integer.MIN_VALUE正しく処理しません。それを修正するために否定する代わりに、符号ビットをマスクすることができます。
-CodesInChaos

1
この単純なアプローチでは、ビットセットに2 ^ 32ビット= 4 Gib = 512 MiBが必要です。これは、32ビットシステム上でも、RAMの適度な量です。
CodesInChaos

選択した言語にビットセットが組み込まれていない場合は、バイト配列を使用してビットセットをエミュレートします。C#の例:bool GetBit(byte[] byteArray, uint index) { var byteIndex = index >> 3; var bitInByte = index & 7; return (byteArray[byteIndex] >> bitInByte) & 1 != 0; }
CodesInChaos

1
@JoulinRouge(およびJacquesB)したがって、これは時間的に線形であり、控えめな(1/2ギガ)RAMを使用し、I / Oのパスを1つだけ取ることに同意します。私のために働く。
user949300

5

この問題は、ビットの配列(true / false)を使用して解決できます。これは、特定の番号が見つかったかどうかを保持するために配列のインデックスを使用して、すべての番号の答えを保持するための最も効率的な構造でなければなりません。

C#

var bArray = new BitArray(Int32.MaxValue);

//Assume the file has 1 number per line
using (StreamReader sr = File.OpenText(fileName))
{
        string s = String.Empty;
        while ((s = sr.ReadLine()) != null)
        {
            var n = int32.Parse(s);
            bArray[n] = true;
        }
}

次に、配列を繰り返し処理しますが、まだfalseである値については、ファイルにはありません。

ファイルを小さなチャンクに分割することもできますが、Windows 7(64ビット)を実行している16.0 GBのラップトップに完全なint32最大サイズの配列(2147483647)を割り当てることができました。

64ビットを実行していなくても、より小さいビット配列を割り当てることができました。ファイルを前処理して、使用可能な環境リソースに適した[0-64000] [64001-128000]などの番号の範囲を持つ番号の小さいファイルのセットを作成します。大きなファイルを調べて、それぞれの番号を対応するセットファイルに書き込みます。次に、小さなファイルをそれぞれ処理します。前処理ステップのために少し時間がかかりますが、リソースが限られている場合はリソースの制限を回避できます。


これは負の数を処理していないようです。(または、入力の場合、最上位ビットが設定された符号なし整数。)ビットセットのメモリは、ほとんどの32ビットシステムでも問題になりません。
user949300

@ user949300-正しい。配列がすべて偽の値で初期化されたとき、私は大きなメモリ消費に気付きませんでした。負の数には、セカンダリBitArrayが必要です。多分bArrayNegative = new BitArrary(Int32.MaxValue)。数値が読み取られたときに、正または負の値を確認し、適切なビット配列に入れることができます。コメントをありがとう。
ジョンレイナー

2

これは面接の質問なので、面接官に制約についての理解を示します。それでは、「すべての可能な数」とはどういう意味ですか?皆が推測するように、本当に0 ... 2 <(32-1)ですか?通常の32ビットアーキテクチャは、32ビット以上の数を扱うことができます。明らかに、単なる表現の問題です。

32ビットシステムで解決する必要がありますか、それとも数字の制限の一部ですか?たとえば、一般的な32ビットシステムでは、ファイルを一度にRAMにロードすることはできません。また、32ビットシステムでは、ファイルサイズの制限により、すべての数字を含むファイルを作成できないことがよくあります。まあ、「これらの4つを除くすべての数字」のような巧妙なエンコーディングがなければ、問題は簡単に解決されます。

しかし、「0から2 ^(32-1)までのすべての数字を含むファイルを指定して、不足しているものを教えてください」という質問を本当に理解したい場合は(これは大きな場合です!)、それを解決する方法はたくさんあります。

些細だが実行不可能:各可能な番号について、ファイルをスキャンし、そこにあるかどうかを確認します。

512 MBのRAMとシングルパスファイル:ファイルから読み取られたすべての番号をマーク(=そのインデックスにビットを設定)し、その後、RAMを1回通過して不足しているものを確認します。


1
いくつかの良い質問ですが、32ビットシステムがint、float、またはhuzziwigsのいずれを表している場合でも、32ビットで2 ^ 32値しか表すことができません。質問が「そうそう、128ビットの超ロングを許可する」の場合、質問の32ビットアーキテクチャの「制約」は意図的に誤解を招く可能性があります。それでも、多くの仕様が誤解を招くか不十分に書かれているため、インタビュアーに尋ねるのは素晴らしい質問です。実際のソリューションは、私のようなBitSetです。
user949300

@ user949300はい-インタビュアーが探しているものを知ることは不可能です。彼らが最後に雇った人が「考える前にスタックをハッキングする」人だった場合、あなたの答えは「アーキテクチャについてまったく知らない」や「最適化ゲームをする」人だった場合とは異なるはずです。:)私は以前に(Javaではないが)大きなビットセットで作業したことがあるので、自然に頭に浮かびます。必要に応じて、低メモリにも適用できます(バケット化)。ビットセットは、512 MBのRAMを使用して、上記のコメントの「ソート問題」を線形時間で解決します。
栄子

0

覚えやすく、面接で明言しやすいアプローチの1つは、Nビットのすべての数値を見ると、各ビットがそれらの値のちょうど半分に設定され、他の半分には設定されないという事実を使用することです。

ファイル内のすべての値を反復処理し、最後に32個の値を保持すると、正確に(2 ^ 32/2)またはその値よりわずかに小さい32個の値になります。最大(2 ^ 32/2)と合計の差により、欠損値の各位置に設定された合計ビットが得られます。

それが得られたら、それらの合計を与える可能性のある4つの値のすべての可能なセットを決定できます。その場合、ファイルの値を再度調べて、それらの組み合わせの一部である値を確認できます。見つかった場合、その値を含む組み合わせは可能性として排除されます。可能な組み合わせが1つだけ残ったら、答えてもらいます。

たとえば、ニブルを使用すると、次の値があります。

1010
0110
1111
0111
1101
1001
0100
0101
0001
1011
1100
1110

各位置に設定される合計ビットは次のとおりです。

7867

それらを8(4 ^ 2/2)から減算すると、次のようになります。

1021

つまり、次の4つの値の可能なセットがあるということです。

1000
0000
0011
0010

1010
0001
0010
0000

(見逃した場合はご容赦ください、私はこれを一目で見ているだけです)

元の数字をもう一度見ると、1010がすぐに見つかります。これは、最初のセットが答えだったことを意味します。


しかし、1つではなく4つの数字を見つける必要があります
-freedev

@freedevあなたは正しいです。それがそれです。4つの数字のセットは、4つの数字です...セットで。
ジミージェームズ

興味深いが、あなたは上に光沢をつけdetermine all the possible sets of 4 values that could give those totalsます。これはあなたの答えに欠けている解決策の重要な部分だと本当に思います。また、時間とスペースの複雑さに影響を与える可能性があります。
アロングラネレク

@AllonGuralnekあなたは正しい。私はこれを少し時間をかけて過ごし、4つの数字のセットが最悪の場合に同じ数字になることを非常に過小評価していました。これは救いのできるアイデアだと思いますが、ここで説明したよりも少し複雑です。詳細は後で更新します。フィードバックに感謝します。
ジミージェームズ

0

ファイルが増加する番号でソートされていると仮定します。

確かに(2³²-4)の数字が含まれていることを確認してください。
ファイルが完全な場合(または、4つの欠落した数字が最後の4つの数字であった場合)、ファイルの位置Nで単語を読み取ると、一致する値Nが返されます。

位置[0..2³²-4-1)で二分法検索を使用して、最初の予期しない番号X1を検索します。
最初の不足している番号が見つかったら、位置[X1 ..(2³²-4-1)]で再度二重検索を実行して、2番目の不足しているX2を見つけます。不足している番号がなくなった場合(1つの不足している番号を渡したため)。
残りの2つの数値についても同様に繰り返します。3回目の反復では、位置Nの単語を読み取るとN-2が返され、4回目にはN-3が返されます。

警告:これはテストしていません。しかし、私はそれがうまくいくと思う。:)

現実には、他の答えにも同意します。最初の質問は環境に関するものです。RAMがありますか(どれだけ)、ファイルはダイレクトアクセスストレージデバイスにありますか、これはワンショット操作(最適化は不要)または重要な操作(各サイクルカウント)ですか、外部ソートユーティリティがありますかなど。
その後、コンテキストに合った妥協案を見つけます。これは少なくとも、アルゴリズムを探す前に問題の分析を開始することを示しています。


-2

すべての標準的な質問と同様、解決策はインタビューの前にグーグルでグーグルすることです。

この質問とバリエーションには、すべての数値のXOR演算を含む非常に明確な「正しい」答えがあります。データベースまたは何かのインデックスを理解することを示すことになっています。したがって、「機能する可能性はあるが、論文で述べられていることではない」という答えはゼロです。

プラス面には、これらの質問の有限セットがあり、数時間の修正により、天才のように見えます。頭の中でそれを解決しているふりをすることを忘れないでください。

編集。ああ、4ではXORとは異なるアプローチがあるようです

http://books.google.com/books?id=415loiMd_c0C&lpg=PP1&dq=muthukrishnan%20data%20stream%20algorithms&hl=el&pg=PA1#v=onepage&q=muthukrishnan%20data%20stream%20algorithms&f=false

編集。Downvoters:これは、OPに記載されている正確な問題に対する公開された教科書O(n)ソリューションです。


1
特に、このリンクされた本はすべてストリーム処理に関するものです。特に、制約内のストリーム処理。それは私が確かに、言ったでしょう、それはそう非常に簡単ですので、これは、OPが見てきた問題の起源であると信じています。さらに注目すべきは、あなたが実際に質問に答えていないことです。これを「元の」または「意図した」質問として納得させて解決策説明できるなら、あなたは私から+1を得るでしょう...しかし、これは何も答えません。
svidgen

1
このインタビュー(インタビュー)は、あなたが本を読んだことを示しています。あなたのスキルや思考プロセスについては何もありません。インタビューの前に、「標準の質問をすべてグーグルで検索する」方法は?私が見逃した「インタビューで尋ねられたすべての質問」の有限リストはありますか?
user949300

1
@ewanは、良い候補者を雇うことの難しさも強調しています!「良い」人がインタビューの質問に対して単に十分に準備されている場合...私のビジネス上の問題を実際に解決できる人を雇うことは難しくなりますか?
svidgen

1
@ewan明確にするために、私は間違った句読点をからかっいました。...いずれにせよ、私はまた、このような標準的な質問と回答にかなり無知であっても、私の日にかなりの数の求人を受け取ったことに留意してください。そして今、採用マネージャーとして、私は答えを暗示したくないことを約束することができます...しかし、私は一部のマネージャーが異なるニーズを持っていることを理解しています。
svidgen

1
意図したように、私のトーンが受信されなかった場合、私はまた、もう一つのことを明確にすべき@Ewan:あなたがすべきである「意図した質問、」実際にリンク先のブックの問題であることを主張することあなたの答えを改訂 そして質問に答えてください!...間違いなくあなたは私の+1 持っているだろうし、他の人もたくさんいるだろう
svidgen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.