山から靴下を効率的にペアリングするにはどうすればよいですか?


3912

昨日、きれいな洗濯物から靴下をペアにしていて、自分のやり方があまり効率的でないことに気付きました。私は素朴な検索を行っていました。靴下を1つ選び、そのペアを見つけるために山を "反復"しました。これは、N / 2×N / 4 = Nにわたって繰り返す必要と2平均オン/ 8靴下。

コンピューターサイエンティストとして、自分にできることを考えていました。O(NlogN)ソリューションを実現するために、(サイズ/色/ ...に従って)並べ替えを行うことはもちろん思いつきました。

私は靴下を複製することができないので、ハッシュまたは他のインプレースソリューションはオプションではありません(できればいいのですが)。

したがって、質問は基本的には次のとおりです。

要素nを含む靴下のペアの山2n(各靴下に一致するペアが1つだけあると想定)が与えられた場合、それらを対数の余分なスペースまで効率的にペアにする最良の方法は何ですか?(必要に応じて、その量の情報を思い出せると思います。)

以下の側面に対処する回答をいただければ幸いです。

  • 膨大な数の靴下の一般理論的ソリューション。
  • 靴下の実際の数はそれほど多くありません、私は私の配偶者を信じていません、そして私は30足以上持っています。(そして、私の靴下と彼女の靴下を区別するのはかなり簡単です。これも使用できますか?)
  • 要素の明確性の問題と同等ですか?

448
私は鳩の穴の原理を使用して、洗濯物の山から1つを正確にペアリングします。私は靴下の3つの異なる色(赤、青、緑)と各色の2ペアを持っています。毎回靴下を4つ選び、いつもペアで靴下を履いて仕事をしています。
Srinivas 2013年

59
さらに別の鳩の穴の原則:n / 2 +1の靴下のサブセットを使用する場合、このサブセットには少なくとも1つのペアが必要です。
wildplasser 2013年

40
すばらしい質問です。あなたは、杭のうち、2つの整合靴下を引く確率の議論で関連問題についての私の記事に興味があるかもしれない:blogs.msdn.com/b/ericlippert/archive/2010/03/22/...
エリックリッペルト

336
子をスポーンしwaitpidて、親として靴下を自分で選別しないようにしてみませんか?
Mxyk 2013

137
私は白いニーハイソックスを所有するだけでこの問題を解決しました。それらはすべて一致します。パイルから任意の2つの靴下をランダムにつかむだけで、それらは一致します。私は靴下をペアにしないことで問題をさらに単純化します。私は靴下の引き出しを持っているので、靴下をペアにせずに、すべての靴下に入れます。私は毎朝引き出しからランダムに2つをつかみます。O(0)に簡略化しました。それよりも簡単なものはありません。:)
リー

回答:


2450

並べ替えのソリューションが提案されていますが、並べ替えは少なすぎます。順序は必要ありません。平等グループが必要ですです。

したがって、ハッシュで十分です(より高速です)。

  1. 靴下の色ごとにパイルを作ります。入力バスケットのすべての靴下を反復処理し、それらをカラーパイルに分配します
  2. 各パイルを反復処理し、他のメトリック(パターンなど)で2番目のパイルセットに分配します。
  3. すべての靴下を視覚的にすぐに処理できる非常に小さな山に分配するまで、このスキームを再帰的に適用します

この種類の再帰的なハッシュパーティション分割は、実際にはSQL Serverによって行われています、巨大なデータセットに対して結合またはハッシュ集計をハッシュする必要がある場合。ビルド入力ストリームを独立した多くのパーティションに分散します。このスキームは、任意の量のデータと複数のCPUに線形にスケーリングします。

各バケットが非常に速く処理されるのに十分なほど小さい十分なバケット提供する分散キー(ハッシュキー)を見つけることができる場合、再帰的なパーティション分割は必要ありません。残念ながら、靴下にはそのような特性はないと思います。

各靴下に「PairID」と呼ばれる整数がある場合、PairID % 10(最後の桁)に従ってそれらを10個のバケットに簡単に分散できます。

私が考えることができる最高の実世界の分割は、山の長方形を作成することです。1つの次元は色で、もう1つの次元はパターンです。なぜ長方形?なぜなら、パイルへのO(1)ランダムアクセスが必要だからです。(3D 立方体も機能しますが、あまり実用的ではありません。)


更新:

並列処理についてはどうですか?複数の人間が靴下をより速く合わせることができますか?

  1. 最も単純な並列化戦略は、複数のワーカーが入力バスケットから取り出して靴下をパイルに置くことです。これは非常に大きくなるだけです-10人の山を越えて戦う100人を想像してみてください。同期のコスト(自分自身を衝突や人間のコミュニケーションとして表現する)は、効率とスピードアップを損ないます(ユニバーサルスケーラビリティ法を参照してください!)。これはデッドロックを起こしやすいですか?いいえ。各ワーカーは一度に1つのパイルにアクセスするだけでよいためです。「ロック」が1つだけの場合、デッドロックは発生しません。人間が山へのアクセスを調整する方法によっては、ライロックが可能になる場合があります。ランダムバックオフを使用するだけかもしれませんネットワークカードのように、物理レベルでこれを実行して、ネットワークワイヤーに排他的にアクセスできるカードを決定します。NICで機能する場合は、人間でも機能するはずです。
  2. 各ワーカーが独自のパイルセットを持っている場合ほぼ無制限にスケーリングされます。ワーカーは、入力バスケットから靴下の大きなチャンクを取り出すことができ(めったに実行していないため、競合はほとんどありません)、靴下を配布するときに同期する必要はありません(スレッドローカルパイルがあるため)。最後に、すべての労働者は杭セットを結合する必要があります。ワーカーが集約ツリーを形成している場合、O(log(ワーカー数*ワーカーあたりのパイル))でそれを実行できると思います。

どのような要素の明瞭さの問題?記事で述べているように、要素の明確性の問題はで解決できますO(N)。これは靴下の問題と同じです(またO(N)、1つの配布ステップのみが必要な場合(人間が計算が得意でないために複数のステップを提案しました-を配布する場合、1つのステップで十分です。md5(color, length, pattern, ...)つまり、すべての属性の完全なハッシュ)。)

明らかに、1よりも速く進むことはできないO(N)ため、最適な下限に達しました。

出力はまったく同じではありませんが(1つのケースではブール値のみ。もう1つのケースでは靴下のペア)、漸近的な複雑さは同じです。


72
これがまさに私がすることです!私は靴下の開口部のスタイルに応じてパイルを作成します(私は白しかない)。これにより、それぞれをすばやく一致させるのに十分な「バケット」が得られます。
Scott Chamberlain

30
私は靴下でこれを試しました(私は簡単に30足以上のペアを持っています)、それは速いです。私が見つけた問題の1つは、十分なハッシュアルゴリズム(パターンのない白い靴下がたくさんある)が得られないために難しくなることです。その場合、それを行うための最適な方法は何でしょうか?
NothingsIspossible

56
@NothingsImpossibleは、ハッシュ衝突攻撃が貧弱なWebサーバーのように感じる方法です!白い靴下はいくつかの属性で区別できますか?あなたがそれらを配布できる何かがあるはずです。それ以外の場合は、任意にペアを形成できます。
usr

37
これは基数ソートで、正解です。@MarkPetersルックアップテーブルは必要ないと思います。靴下を1回直線で通過すると、靴下が数値ベクトルに変換され、「靴下セグメント」のバケットへのマッピングが簡単になります。靴下をストリングでベクターに結び付けることができるので、最後に別の線形パスを必要としません。
先のとがっ

49
私が大学に通った男は、実際にPairIDを持っていました。靴下の各ペアに糸で縫い付けられました:1、2、3、4 ...
Ryan Lundy

579

人間の脳のアーキテクチャは現代のCPUとは完全に異なるため、この質問は実際には意味がありません。

人間は、「一致するペアを見つける」ことが、大きすぎないセットの1つの操作になり得るという事実を利用して、CPUアルゴリズムに勝つことができます。

私のアルゴリズム:

spread_all_socks_on_flat_surface();
while (socks_left_on_a_surface()) {
     // Thanks to human visual SIMD, this is one, quick operation.
     pair = notice_any_matching_pair();
     remove_socks_pair_from_surface(pair);
}

少なくともこれは私が実際に使用しているものであり、非常に効率的です。欠点は、平面が必要なことですが、通常は豊富です。


229
靴下の数が増えるにつれ、人間のSIMDはCPUに勝るものになりません。
Lie Ryan

25
最良の答えは、IMOです。日常の問題をコンピューターアルゴリズムにまで減らすのは楽しくて賢い(そしてSOに適しています)が、人の目や脳の解像力を最大60足程度の靴下に使用するほうが理にかなっています。
drug_user841417 2013年

13
@LieRyan靴下が均一に分布している場合、誕生日のパラドックスが原因で十分に小さい靴下のセットに気づくようになります(色を任意の精度で区別できない限り、私はこれを疑います)、ここでのボトルネックは発生しません。人間のカラーマッチングアルゴリズムですが、拡散ステップです。
トーマス

13
@ dpc.ucore.infoいいえ。織り込まれた袖口のパターン、袖口の長さ、全長、黒の色合いが異なるためです(妻はおそらく最後の1つで肉体的に傷つくでしょう)。
クリスチャン

200
靴下の数が偶数であるとよいでしょう。そうでなければ、長い間靴下を折りたたむことになります...
Patrick James McDougle 2013年

258

ケース1:すべての靴下は同じです(ちなみにこれは私が実際にやっていることです)。

それらのいずれか2つを選択してペアを作成します。一定の時間。

ケース2:組み合わせの数は一定です(所有権、色、サイズ、テクスチャなど)。

基数ソートを使用します。比較が必要ないため、これは線形時間にすぎません。

ケース3:組み合わせの数が事前にわかっていない(一般的なケース)。

2つの靴下がペアになっているかどうかを確認するには、比較を行う必要があります。のいずれかを選択O(n log n)比較ベースのソートアルゴリズムのます。

ただし、靴下の数が比較的少ない(一定の)現実の生活では、これらの理論的に最適なアルゴリズムはうまく機能しません。理論的には2次時間を必要とする順次検索よりもさらに時間がかかる場合があります。


8
>理論的には2次時間が必要な順次検索よりもさらに時間がかかる場合があります。ええ、そういうわけで私はこれをするのが嫌いです、多分私は靴下をすべて捨てて、ケース1から始めるべきです
Nils

57
すべて同じ靴下を持っていることの欠点は、それらが異なる速度で老化する傾向があることです。したがって、あなたはまだそれらがどのように着用されているかに基づいてそれらを一致させようとすることになります。(単純にパターンで照合するよりも難しい)
SDC

118
「ペアにするのが簡単になるため」、同一のソックスを60足持つことの問題は、コンピュータで作業しているような印象を与えることです。
スティーブアイブス

13
ケース1は、ペアを一緒に折りたたむなどの操作が含まれる一定の時間ではありません。この場合、それは最小の定数因子をもつ線形時間です(その証明は読者の練習問題として残します)。一つは、おそらく1組と靴下の完全なバケツ折りたたみ同じ時間を取ることができません。ただし、線形にスケーリングします。アムダールの法則により、オーバーヘッドを無視して無制限にスピードアップします。グスタフソンの法則により、オーバーヘッドを無視して、十分な数のワーカー(リーダーの演習として残される量)が与えられれば、1ペアをフォールドするのに必要な数だけペアをフォールドできます。
acelent

7
@PauloMadeira並べ替えは一定の時間です-パイルを取り出して引き出しに入れるだけです。この場合の唯一の操作は、靴下を足に置くことですが、これも一定です。パフォーマンスは、おそらくスペースを犠牲にすることで、靴下着用の据え置き実行によって得られます(折り畳まれていない靴下の消費スペースは、折り畳まれた靴下よりも大きい)。これは価値があると私は主張します。私は通常、妻とこの議論を失います。
Travis

157

非アルゴリズム的な答えですが、私がそれを行うと「効率的」です。

  • ステップ1)既存の靴下をすべて破棄します

  • ステップ2)に行く ウォルマートに、白のパケット10個と黒のパケット10個のパケットでそれらを購入します。日常生活で他の色は必要ありません。

それでも時々、私はこれをもう一度行う必要があります(靴下の紛失、損傷した靴下など)、私は頻繁に完全に良い靴下を破棄するのが嫌いです(そして私は彼らが同じ靴下のリファレンスを販売し続けたかったのです!)別のアプローチ。

アルゴリズムの答え:

あなたがしているように、靴下の2番目のスタックに対して靴下を1つだけ描画する場合よりも考慮してください。単純な検索で一致する靴下を見つける確率は非常に低いです。

  • ランダムに5つ選んで、形や長さを覚えてください。

なぜ5つ?通常、人間は良いですが、ワーキングメモリ内の5〜7個の異なる要素を覚えています。人間のRPNスタックに少し似ていますが、5つが安全なデフォルトです。

  • 2n-5のスタックから1つをピックアップします。

  • 次に、描いた5つの内部で一致(視覚的なパターンマッチング-小さなスタックを使用すると人間がうまくいく)を探します。見つからない場合は、5に追加します。

  • スタックからランダムに靴下を選んで、5 + 1靴下と比較してください。スタックが大きくなると、パフォーマンスは低下しますが、確率が上がります。はるかに高速。

一致のオッズが50%になるまで描画する必要があるサンプルの数を計算するための式を自由に書き留めてください。IIRCそれは超幾何法則です。

私は毎朝それを行い、めったに3つ以上のドローが必要になることはありませんが、n似たようなm形の白い靴下のペア(失われたものを10個くらい与えるか、持っていきます)を持っています。今、あなたは私の株式のスタックのサイズを推定することができます:-)

ところで、ペアが必要になるたびにすべての靴下を並べ替えるトランザクションコストの合計は、一度実行して靴下をバインドするよりもはるかに少ないことがわかりました。靴下を縛る必要がないため、ジャストインタイムの方が効果的です。限界収益率も低下します(つまり、洗濯物のどこかにあるときに必要な靴下を2つか3つ探し続けます)あなたの靴下とのマッチングを完了すると、あなたはそれで時間を失います。


25
「非アルゴリズム」の回答に賛成票を投じます。これはまさに私がすることであり、それは素晴らしい働きをします。洗った靴下を後ろに置き、朝に引き出しの前から引っ張って靴下を「回転」させる場合、交換の問題は問題になりません。すべての靴下は均一に着用します。1つの摩耗に気づき始めたとき、私は買い物リストに入れて、靴下のそのクラス全体を完全に置き換えます。古い靴下の場合、私は最高の20%をグッドウィル(食料雑貨の袋に入れて、混じり合わないようにする)に与え、残りを売り込みます。あなたは靴下を無駄にしていません。この時点で、80%はとにかく6か月しか残っていません。
FastAl、2013年

2
ところで(1)靴下をバインドすると、伸縮性のある靴下が伸ばされた状態で保管され、がはるかに速く失敗します。あなたが持っているユニークな靴下の種類を制限すると、拘束力が失われます。(2)ユニークな靴下を制限することの不利な点は、特定のファッションの懸念を持つ人々にとって、この方法は適切ではないかもしれないということです。
FastAl、2013年

3
「非アルゴリズム」の回答を投稿するためにここに来ました。真のコンピュータサイエンスと同様に、ほとんどの人はデータとその構造に十分な注意を払うことはありません。
bkconrad 2013

私は毎朝このアルゴリズムのアプローチを使用し、それは魅力のように機能します!さらに、使い古した靴下を別の山に置き、後で捨てます(残念ながら、ゴミ箱に入れる時間を見つける前に、元の山に戻ることができました)。
DonatasOlsevičius2013

3
«白のnパケットと黒のmパケット。日常生活で他の色を使用する必要はありません»靴下を簡単に選択するための優れた標準ルールは、実際にはズボンの色またはベルトの色のいずれかに一致することです。このため、最も一般的に使用される色は、おそらく黒、青、灰色、そしていくらかの茶色です。多くの白い靴下が必要だとは信じがたいです。
Andrea Lazzarotto、2015

106

私がしていることは、最初の靴下を手に取り、それを下に置くことです(たとえば、洗濯ボウルの端に)。次に、別の靴下を取り上げて、最初の靴下と同じかどうかを確認します。ある場合は、両方削除します。そうでない場合は、最初の靴下の横に置きます。次に、3番目の靴下を取り上げ、それを最初の2つと比較します(まだそこにある場合)。等。

この方法は、「靴下を取り除く」という選択肢があるとすれば、かなり簡単に配列に実装できます。実際には、靴下を「取り除く」必要さえありません。靴下を並べ替える必要がない場合(以下を参照)、それらを移動して、すべての靴下を配列でペアに配置した配列を作成できます。

靴下の唯一の演算が等しいかどうかを比較することであると仮定すると、このアルゴリズムは基本的にはまだn 2アルゴリズムですが、平均的なケースについてはわかりません(それを計算する方法は知りません)。

もちろん、並べ替えを行うと効率が向上します。特に、他の2つの靴下の間に靴下を簡単に「挿入」できる実際の生活においてはそうです。計算では同じことをツリーで実現できますが、それは余分なスペースです。そしてもちろん、NlogNに戻ります(並べ替え基準によって同じであるが、同じペアからではない複数の靴下がある場合は、もう少し)。

それ以外は何も思いつきませんが、この方法は実生活ではかなり効率が良いようです。:)


7
これも私がやっていることです(単にスペースを空けると、挿入もO(1)になることに注意してください)。ただし、理論的には多数の靴下を使用すると、スケーリングが不十分になります。
Mooing Duck 2013

15
理論的に多数の種類の靴下ではスケールが不十分
Steven Lu

@StevenLu-私が言ったように-ソートするかどうかに応じて、n * nまたはnLognです。そのため、他の並べ替えアルゴリズムと比べて、スケーリングが不十分です。より速くしたい場合は、番号を付けて基数ソートを使用します。
Vilx-2013年

これは基本的に、一致するが一致しないソックスをハッシュベースのルックアップに格納します。理想的なハッシュではO(n)ですが、十分な靴下が格納されていて、ハッシュが縮退し始めると、それに応じてさらに複雑になります。
Jon Hanna

3
他の2つの靴下の間に靴下を挿入すると、靴下のペアリングの目的にどのような価値がありますか?靴下の基数はありません。:-x
JoeBrockhaus

60

これは間違った質問をしています。正しい質問は、なぜ靴下の選別に時間を費やしているのですか?選択したX通貨単位の空き時間を重視する場合、年間ベースでいくらかかりますか?

そして、多くの場合、これは単なるされていない任意の、それは自由な時間だあなたがベッドの中で過ごしたり、あなたのコーヒーをすすりながら、または早期ビットを残し、渋滞に巻き込まれていないことができた、自由時間。

多くの場合、一歩下がって問題を回避する方法を考えます。

そして方法があります!

好きな靴下を見つけてください。すべての関連機能を考慮してください。さまざまな照明条件での色、全体的な品質と耐久性、さまざまな気候条件での快適さ、臭気の吸収。また、重要なのは、保管中に伸縮性を失わないようにする必要があるため、天然の布地は良好であり、プラスチックのラッピングで利用できることです。

左足ソックスと右足ソックスに違いがなければより良いですが、それは重要ではありません。靴下が左右対称である場合、ペアを見つけることはO(1)操作であり、靴下を並べ替えることはおおよそのO(M)操作です。小さな定数。

左右の靴下が異なるファンシーペアを選択した場合、フルバケットソートを左右の足のバケットに実行するとO(N + M)がかかります。Nは靴下の数、Mは上記と同じです。他の誰かが最初のペアを見つける平均反復の式を与えることができますが、ブラインドサーチでペアを見つけるための最悪のケースはN / 2 + 1であり、合理的なNの場合は天文学的にありそうもないケースになります。これは、高度な画像を使用することで高速化できますMk1 Eyeball並べ替えられていない靴下の山をスキャンするときの認識アルゴリズムとヒューリスティック。

したがって、O(1)靴下ペアリング効率を達成するためのアルゴリズム(対称靴下を想定)は次のとおりです。

  1. 残りの人生で必要になる靴下の数を見積もる必要があります。または、おそらく靴下を履く必要がなく、引退して暖かい気候に移動するまでです。若い場合は、すべての家に靴下選別ロボットが設置されるまでにかかる時間を見積もることができ、問題全体が無関係になります。

  2. 選択した靴下をまとめて注文する方法とそれがいくらかかるか、そしてそれらが配達する方法を見つける必要があります。

  3. 靴下を注文!

  4. 古い靴下を脱いでください。

代替のステップ3には、長年にわたって同じ量のおそらくより安い靴下を数ペアずつ購入するコストを比較し、靴下を並べ替えるコストを追加することが含まれますが、私の言葉を借りると、一括購入の方が安いです!また、ストレージの靴下は株価の上昇率で価値が高まるため、多くの投資で得られる以上の価値があります。その場合も収納コストはかかりますが、靴下はクローゼットの一番上の棚にあまりスペースを取りません。

問題が解決しました。だから、新しい靴下を手に入れ、古い靴下を捨てる/寄付し、あなたが残りの人生のために毎日お金と時間を節約していることを知った後、幸せに暮らしてください。


生涯(75年と想定)の靴下(1か月に4ペアを排出すると仮定すると、3600ペアになる)の供給(合計で新しい靴下のペアが20立方インチを想定すると)は、合計1 1/2立方ヤードになります。それは膨大なスペースです。彼らがおおよそ立方体である箱でそれをあなたに届けると仮定すると、その木枠は一辺が約3フィート4インチになります。
AJMansfield 2013

2
@AJMansfieldの有効な懸念。しかし、私はあなたの数のいくつかに同意しません。私はたったの40年(25 ... 65)の期間をとります(親、寮などに住んでいないから引退するまでの時間、上記を参照)。また、元のパッケージでは、1ペアは0,5x4x6インチのようになります。これらの数はあなたのスペースのエスタイムをかなりダウンさせます!
ハイド

ステップ4は不必要に無駄です、-1。
Dan Bechard、2013年

2
AJMansfieldの測定値に混乱する可能性がある他の人のためのガイド、メトリックへの変換:»合計1.14m³を占める(新しい靴下のペアが327cm³を想定すると仮定)。それは膨大なスペースです。彼らがおおよそ立方体である箱でそれをあなたに届けると仮定すると、その木枠は一辺が約1.04 mになるでしょう。«
Joey

好奇心に基づく質問を「間違った質問」にするにはどうすればよいですか?クラシックStackOverflow ...
Timmmm

52

理論上の制限はO(n)です。これは、各靴下に触れる必要があるためです(一部がすでに何らかの方法でペアリングされている場合を除く)。

基数ソートで O(n)を実現できます。バケットの属性をいくつか選択するだけです。

  1. まず、(彼女、私の)を選択できます-それらを2つの山に分割し、
  2. 次に、色を使用します(たとえば、色の名前でアルファベット順に色を並べることができます)-それらを色ごとに山に分割します(同じ山にあるすべての靴下について、手順1の最初の順序を維持することを忘れないでください)。
  3. 靴下の長さ
  4. その後、テクスチャ、...

限られた数の属性を選択できるが、各ペアを一意に識別できる十分な属性がある場合、O(k * n)で実行する必要があります。kが制限されていると見なせる場合はO(n)です。


3
靴下は、4パック以上のサイズで提供されることがよくあります。それは、安価だからですが、それも区別がつかなくなるからです。これに対抗するために、妻は私が購入する靴下の新しいペアごとに小さなマークを縫い付けます。マークはペアごとに色が異なるか、色がなくなった場合は形状が異なります。このアプローチでは、限られた属性のセットさえ必要ありません。各ペアに一意の番号を縫うだけです。:)追加のポイントについては、バイナリを使用します。
Vilx-2013年

29
@ Vilx-なぜ?!?それらが区別できないという全体のポイントではありませんか?
2013年

2
@flup-全体のポイントは、より大きなバンドルで販売することだと思います。:)私にとっては、これはペアでそれらを着用するのに役立ちます。それ以外の場合は、非常にすり減った3つの靴下と1つの新しい靴下になる可能性があります。ちょっとばかげた。
Vilx-2013年

13
O(n)の計算に同意しません。$ k $とは何ですか?$ k $は属性の数です。$ k $は$ O(log n)$であると主張します。これは、各ペアを一意に識別するのに十分でなければならないためです。2つのペア(白黒)がある場合は、色($ k = 1、n = 2 $)で十分です。黒のペアが1つある場合は、短くします。1組の黒、長い。白一組、短い。そして、白の1つのペア、長い-$ k = 2、n = 4 $。次に、$ k $を制限すると、同時に$ n $も制限されます。$ n $を制限する場合、注文計算はもはや意味がありません。
Emory

3
@emory、私は$あなたのものがコードのように見えるようにするために、キャラクターではなくバックティックを探していると思います。
Xymostech 2013年

33

実用的な解決策として:

  1. 簡単に区別できる靴下の山をすばやく作成します。(色で言う)
  2. すべての山をクイックソートし、靴下の長さを比較に使用します。人間としては、最悪のケースを回避するために、どのソックスを使用してパーティション分割するかをかなり迅速に決定できます。(複数の靴下を並行して見ることができるので、それを活用してください!)
  3. すぐにスポットペアやペアにできない靴下を見つけやすいしきい値に達したら、パイルの並べ替えを停止します

1000色の靴下があり、8色と平均的な分布がある場合、c * n時間で各125靴下を4枚重ねることができます。靴下のしきい値が5の場合、すべてのパイルを6回に分けて並べることができます。(靴下を右の山に投げるのに2秒を数えると、4時間もかかりません。)

60の靴下、3色、2種類の靴下(あなたのもの/あなたの妻のもの)しかない場合は、1ランで10靴下のすべての山を並べ替えることができます(再度しきい値= 5)。(2秒を数えると、2分かかります)。

最初のバケットの並べ替えにより、nソックスがc*n時間内にkバケットに分割されるため、c*n*log(k)作業を行うだけで済むため、プロセスがスピードアップします。(しきい値を考慮していません)。ですから、すべてのn*c*(1 + log(k))作業について、cは靴下を山に投げる時間です。

このアプローチは、c*x*n + O(1)ほぼすべての方法と比較して有利log(k) < x - 1です。


コンピュータサイエンスでは、これが役立ちます。n個のコレクションがあります。 ものもそれらの上、オーダー(長さ)と同値関係(追加情報、靴下の例えば色)。同値関係により、元のコレクションのパーティションを作成でき、すべての同値クラスで順序が維持されます。モノの等価クラスへのマッピングはO(1)で行うことができるため、各アイテムをクラスに割り当てるのに必要なのはO(n)だけです。これで、追加情報を使用して、あらゆる方法ですべてのクラスを並べ替えることができます。利点は、データセットがすでにかなり小さいことです。

複数の同値関係がある場合は、メソッドをネストすることもできます->テクスチャのすべてのパイルパーティション内で、長さでソートするよりも、カラーパイルを作成します。ほぼ等しいサイズの2つ以上の要素でパーティションを作成する同値関係は、並べ替えよりも速度が向上します(ただし、靴下をパイルに直接割り当てることができます)。並べ替えは、小さいデータセットで非常に迅速に実行できます。


3
人間の最適化:私は人間として、ステップ2で靴下を大まかに昇順に並べ、シェルソートのように、並べ替えられるまでさらに細かく繰り返します。これは、比較スワップベースのアプローチよりも、人間(視覚的な推定)の方がはるかに高速です。
AndrewC 2013年

28

あなたは間違った問題を解決しようとしています。

解決策1:汚れた靴下を洗濯かごに入れるたびに、小さな結び目で結びます。そうすれば、洗浄後に分別を行う必要はありません。Mongoデータベースにインデックスを登録するようなものだと考えてください。将来的には、CPUの節約のために少し作業を進めます。

解決策2:冬なら、お揃いの靴下を着用する必要はありません。私たちはプログラマーです。それが機能する限り、誰も知る必要はありません。

解決策3:仕事を広める。このような複雑なCPUプロセスを、UIをブロックせずに非同期で実行したいとします。その靴下の山を取り、バッグに詰めます。必要なときだけペアを探してください。そうすることで、必要な作業量が大幅に少なくなります。

お役に立てれば!


5
結び目で靴下(または任意の衣服)を結ぶと、洗濯機が衣服を洗う能力が低下し、衣服をほどくのが難しくなります。解決策2では、状態が長くなるほど保守が困難になります。6か月後、ショートパンツとスニーカーのペアで2枚の黒いアンクルソックスを着用する必要がある場合、6か月間作業しても、同じ状態(ダーティ/クリーン、類似の摩耗)でそのペアを見つける可能性ははるかに低くなります。ソリューション3は、「非同期」ではなく、より単純な「レイジー」です。必要なときに正確に必要な最小限の作業を行う。
KeithS 2017

日時:ソリューション2:人々は、彼らが:)私のBirksでそれらを見ることができますので、私はマッチングの靴下を履いていないよ知っているだろう
ボブ・プロブスト

@BobProbstはい。ただし、他のプログラマーもBirksの比類のない靴下を履いているので、Birksだけではないことに注意してください。
Francesco Pasa、

27

この質問は実際には非常に哲学的です。本質的には、問題を解決する人々の力(私たちの頭脳の「ウェットウェア」)がアルゴリズムによって達成できるものと同等であるかどうかについてです。

靴下の並べ替えの明らかなアルゴリズムは次のとおりです。

Let N be the set of socks that are still unpaired, initially empty
for each sock s taken from the dryer
  if s matches a sock t in N
    remove t from N, bundle s and t together, and throw them in the basket
  else
    add s to N

今、この問題のコンピュータサイエンスはすべてのステップです

  1. 「sがNの靴下tとペアになっている場合」。これまでに見たことをどれだけ早く「記憶」できるでしょうか。
  2. 「Nからtを削除」および「Nにsを追加」。これまでに見たものを追跡するのにどれくらいの費用がかかりますか?

人間はさまざまな戦略を使ってこれらを実現します。人間の記憶連想的であり、格納された値の機能セットが対応する値自体とペアになっているハッシュテーブルのようなものです。たとえば、「赤い車」の概念は、人が覚えることができるすべての赤い車に対応します。完璧な記憶を持つ人は完璧なマッピングを持っています。ほとんどの人はこの点で不完全です(そして他のほとんどの人)。連想マップの容量は限られています。マッピングがブリーブする さまざまな状況下で存在しない(ビールが多すぎる)、誤って記録される(「私は彼女の名前はネティではなくベティだった」)、または真実が変わったことを観察しても上書きされない(「父の車」が呼び起こす) 「オレンジ色の火の鳥」は、彼が赤いカマロと交換したことを実際に知っていたときのことです。

靴下の場合、完全な再現とは靴下を見ることを意味します s常に兄弟の記憶が生成tしますt。写真の記憶を持つ人は、1と2の両方を確実に一定の時間で達成します。

完全ではない記憶力を持つ人は、追跡する機能内の機能に基づいて、いくつかの常識的な等価クラスを使用する可能性があります:サイズ(papa、mama、baby)、色(緑がかった、赤みがかったなど)、パターン(argyle、plainなど) 、スタイル(フーティー、ニーハイなど)。したがって、アイロン台は、カテゴリごとにセクションに分かれています。これにより、通常、カテゴリはメモリによって一定の時間に配置されますが、カテゴリ「バケット」を介した線形検索が必要です。

記憶も想像力もまったくない人(申し訳ありません)は、靴下を1つの山にまとめて、山全体の線形検索を実行します。

きちんとしたフリークは、誰かが示唆するようにペアに数値ラベルを使用するかもしれません。これは、完全な順序付けへの扉を開き、人間がCPUで使用するのとまったく同じアルゴリズム(バイナリ検索、ツリー、ハッシュなど)を使用できるようにします。

したがって、「最良の」アルゴリズムは、それを実行しているウェットウェア/ハードウェア/ソフトウェアの品質と、ペアに合計順序を課すことで「チート」する意欲に依存します。確かに「最良の」メタアルゴリズムは、世界最高のsock-sorterを雇うことです。sock属性セットの巨大なセットNを取得し、すばやく保存できる1-1連想メモリに、一定時間のルックアップ、挿入、そして削除。このような人と機械の両方を調達できます。靴下がある場合は、すべての靴下をNペアのO(N)時間でペアにすることができます。これが最適です。合計注文タグを使用すると、標準のハッシュを使用して、人間またはハードウェアのコンピューターで同じ結果を得ることができます。


それはまだかなり間違っていますが、わかりました。この質問はそれについてではありません。Church-Turingの論文が正しいかどうかに関係なく、人間とコンピューターの両方が靴下を分類できます。(現実にはそれはチューリング機械よりもはるかに少ない計算能力を持っている、非常に有限の実体であること、人間である...と同じことが私たちのコンピュータの真のですが、制限が異なります。)
ジム・Balter

同意しません。もちろん、現在のコンピュータはいずれも、TMではなく本質的に巨大なDFA(モジュロI / O差)です。ただし、私たちの体などのアナログデバイスは、無限のテープをエミュレートできます。心の計算方法に関する有用な特徴付けはまだありません。
ジーン

人間の脳には無限の解像度がなく、それを実現できないため、人間やその他の物理デバイス用の無限のテープはありません。また、神経科学を学ぶのにも役立ちます。いずれにせよ、あなたが一つを注入したいという願望に関係なく、ここには深い哲学的な質問はありませんでした。しかし、あなたが何をするかを信じてください...これはこの種の議論の場ではなく、私は以前に何度もそれを経験しました。しかし、私はいつも、TMと同等であると想像して、最も単純な問題(私たち全員)をかろうじて解決できる人々に面白がっています。
ジムバルター2013

22

コスト:靴下を移動する->高い、靴下を並べて検索する->小さい

私たちがやりたいことは、移動回数を減らし、検索回数で補うことです。また、ホモサピエンスのマルチスレッド環境を利用して、決定キャッシュにより多くのものを保持できます。

X =あなたのもの、Y =あなたの配偶者たち

すべての靴下の山Aから:

2つの靴下を選び、対応するX靴下をX線に、Y靴下をY線に次の使用可能な位置に配置します。

Aが空になるまで行います。

各ラインXおよびY

  1. 行の最初の靴下を選択し、対応する靴下が見つかるまで行に沿って検索します。

  2. 対応する完成した靴下のラインに入れます。

  3. オプションラインを検索していて、現在表示している靴下が以前と同じである場合は、これらの靴下に対して手順2を実行します。

必要に応じて、ステップ1で、2つではなくその行から2つの靴下をピックアップします。キャッシュメモリが十分に大きいので、どちらかの靴下が監視している行の現在の靴下と一致するかどうかをすばやく識別できます。幸運にも3つの腕を持つことができる場合、被験者の記憶が十分に大きいことを考えると、同時に3つの靴下を解析することができます。

XとYの両方が空になるまで行います。

できた

ただし、これは選択ソートと同じくらい複雑であるため、I / O(靴下の移動)と検索(靴下を探す)の速度により、かかる時間ははるかに短くなります。


22

以下は、比較ベースのモデルにおけるOmega(n log n)の下限です。(唯一の有効な操作は2つの靴下を比較することです。)

2nソックスが次のように配置されていることがわかっているとします。

p 1 p 2 p 3 ... p n p f(1) p f(2) ... p f(n)

ここで、fはセット{1,2、...、n}の未知の順列です。これを知っていても問題を難しくすることはできません。あります!可能な出力(前半と後半のマッチング)。つまり、log(n!)= Omega(n log n)の比較が必要です。これはソートによって取得できます。

要素の区別の問題への接続に関心があるので、出力がバイナリのyes / noであるため、要素の区別の境界にあるOmega(n log n)を証明することは困難です。ここで、出力は一致している必要があり、適切な範囲を得るには、可能な出力の数で十分です。ただし、要素の区別に関連するバリアントがあります。2nの靴下が与えられ、それらを一意にペアにできるかどうか疑問に思います。(a 1、a 2、...、a n)を(a 1、a 1、a 2、a 2、...、a n、a n)に送信することにより、EDから削減を得ることができます。(括弧で言えば、EDの硬度の証明は非常に興味深いですトポロジーを介してです。)

同等性テストのみを許可する場合、元の問題のOmega(n 2)限界があるはずだと思います。私の直感は、テスト後にエッジを追加するグラフを考え、グラフが密でない場合、出力は一意に決定されないと主張します。


19

これが私が実際に行う方法です、靴下のpペア(n = 2pの個別の靴下):

  • パイルからランダムに靴下をつかみます。
  • 最初の靴下の場合、または以前に選択したすべての靴下がペアリングされている場合は、靴下を目の前にあるペアになっていない靴下の「配列」の最初の「スロット」に配置します。
  • ペアになっていない靴下を1つ以上選択している場合は、アレイ内のペアになっていないすべての靴下に対して現在の靴下を確認します。
    • 配列を構築する際に、靴下を一般的なクラスまたはタイプ(白/黒、足首/クルー、スポーツ/ドレス)に分離し、「ドリルダウン」して同類のみを比較することができます。
    • 許容できる一致が見つかった場合は、両方の靴下をまとめて、アレイから削除します。
    • そうでない場合は、現在の靴下をアレイの最初の開いているスロットに入れます。
  • すべての靴下で繰り返します。

このスキームの最悪のシナリオは、靴下のすべてのペアが完全に一致する必要があるほど十分に異なり、最初に選択するn / 2の靴下がすべて異なるというものです。これはO(n 2)のシナリオであり、非常にありそうもありません。靴下tの一意のタイプの数がペアの数p = n / 2未満であり、各タイプの靴下が(通常は摩耗関連の用語で)十分に似ていて、そのタイプの靴下を任意の靴下と組み合わせることができる場合その他、次に私が上で推測したように、比較する必要がある靴下の最大数はtです。その後、次に引っ張る靴下ペアになっていない靴下のいずれかと一致します。このシナリオは、平均的な靴下の引き出しで最悪の場合よりもはるかに可能性が高く、最悪の場合の複雑さをO(n * t)に減らします(通常はt << n)


1
これはおそらく私の精神プロセスにかなり近いです。並べ替え前の最適化のレイヤーを追加しました。運動靴下は白で洗い、ドレスソックスは色で洗います。つまり、2回分の洗濯物を一緒に捨てない限り、靴下はすでに種類別に分類されています。白の負荷は非常に速くなります(多くの同じ靴下)が、ドレスの靴下は時間がかかります。その他の重要なヒント-ソートに使用できるメモリを増やします(最初にすべての非靴下を折りたたんで削除し、次にペアリングアルゴリズムを実行します)
orh

17

現実的なアプローチ:

できるだけ早く、並べ替えられていない山から靴下を1つずつ取り外し、目の前の山に置きます。パイルは、すべての靴下が同じ方向を向くように、ある程度スペース効率よく配置する必要があります。パイルの数は、簡単に到達できる距離によって制限されます。靴下を置く山の選択は、靴下を一見似たような靴下の山に置くことによって、可能な限り迅速に行う必要があります。タイプI(属していないパイルに靴下を置く)またはタイプII(同じようなソックスの既存のパイルがある場合、それ自体のパイルに靴下を置く)エラーは許容できます-最も重要な考慮事項は速度です

すべての靴下がパイルに入れられたら、マルチソックパイルをすばやく通過してペアを作成し、それらを取り外します(これらは引き出しに向かっています)。パイルに一致しない靴下がある場合は、それらを最高のパイル(可能な限り高速の制約内)にパイルします。すべてのマルチソックパイルが処理されたら、タイプIIエラーのためにペアリングされなかった残りのペアリング可能なソックスを一致させます。おっと、これで完了です。靴下はたくさんあるので、大きな部分が汚れるまで洗わないでください。もう1つの実用的な注意:伸縮性のある特性を利用して、靴下のペアの一方を他方の上にひっくり返して、引き出しに運ばれているときも、引き出しの中にいるときも一緒にとどまります。


15

あなたの質問から、あなたは洗濯の経験があまりないことは明らかです:)。少数のペアリングできない靴下でうまく機能するアルゴリズムが必要です。

これまでの答えは、人間のパターン認識機能を十分に活用していません。セットのゲームは、これをうまく行う方法の手がかりを提供します。すべての靴下を2次元空間に配置して、靴下をよく認識し、手で簡単に到達できるようにします。これにより、約120 * 80 cm程度の領域に制限されます。そこから、認識したペアを選択して削除します。空きスペースに余分な靴下を入れて繰り返します。靴下が簡単にわかる人(小さい子供が頭に浮かぶ人)を洗う場合は、最初に靴下を選択して、基数ソートを実行できます。このアルゴリズムは、単一の靴下の数が少ない場合にのみうまく機能します


それが普通のやり方です。残りのすべての靴下を毎回繰り返すよりもはるかにうまく機能します。
yu_ominae 2013年

素晴らしいアプローチで、CSの実際の問題にも適用できると思います。そのような例を追加していただけますか(問題を解決するために同様のアプローチを使用できるCSの問題)?また、このソリューションは何百万もの靴下にどのように対応しますか?
2013年

これは基本的に、ここの他の回答である1月20 日のstackoverflow.com/a/14423956と同じです。両方とも+1です。人間の視覚システムは超並列です。
Will Ness

15

最初の靴下を拾って、テーブルの上に置きます。次に別の靴下を選びます。最初に選択したものと一致する場合は、最初に選択したものの上に配置します。そうでない場合は、テーブルから少し離してテーブルに置きます。3番目の靴下を選びます。前の2つのいずれかに一致する場合は、それらの上に配置するか、3番目から少し離して配置します。すべての靴下を拾うまで繰り返します。


1
これが唯一の有効な答えです。他のすべての人は、ほとんどの時間が類似の靴下を区別するのに費やされているという事実を無視します(したがって、物理的な外観でそれらをすべてまとめると、さらに悪化します)。
entonio 2014

楽しみのために、靴下を小さなpythonプログラムに積み上げるこの方法を書きました 積み上げる gist.github.com/justinfay/53b574cf0a492f6795ef
Justin Fay

12

靴下をパイルからペアリングするのがいかに効率的であるかを説明するには、最初にマシンを定義する必要があります。ペアリングは、チューリングでもランダムアクセスマシンでも行われないためです。アルゴリズム分析。

この機械

機械は、人間と呼ばれる実世界の要素を抽象化したものです。両目で環境から読み取ることができます。そして、私たちの機械モデルは2本の腕を使用して環境を操作することができます。論理演算と算術演算は私たちの頭脳を使って計算されます(うまくいけば;-))。

また、これらの計測器で実行できるアトミック操作の本質的なランタイムを考慮する必要があります。物理的な制約により、腕や目によって実行される操作は、一定でない時間の複雑さを持っています。これは、無限に大きな靴下の山を腕で動かすことも、無限に大きな靴下の山の上にある靴下を見ることもできないためです。

しかし、機械物理学は私たちにもいくつかの良いものを与えます。腕のある靴下の移動は1つに制限されていません。一度に2つずつ移動できます。

したがって、前の分析に応じて、以下の操作を降順で使用する必要があります。

  • 論理演算と算術演算
  • 環境読み取り
  • 環境の変更

靴下の数が非常に限られているという事実を利用することもできます。したがって、環境の変更には、山の中のすべての靴下が含まれる可能性があります。

アルゴリズム

だからここに私の提案があります:

  1. パイルの靴下をすべて床に広げます。
  2. 床にある靴下を見てペアを見つけます。
  3. ペアが作成できなくなるまで2から繰り返します。
  4. 靴下が床になくなるまで1から繰り返します。

靴下を床に広げると、靴下が隠れてしまうことがあるため、操作4が必要です。アルゴリズムの分析は次のとおりです。

解析

アルゴリズムは高い確率で終了します。これは、手順2で靴下のペアを見つけることができないためです。

n靴下のペアをペアリングする次のランタイム分析では、2nステップ1の後で靴下の少なくとも半分が非表示になっていないと仮定します。したがって、平均的なケースではn/2ペアを見つけることができます。これは、ループがステップ4の実行O(log n)回数であることを意味します。ステップ2が実行されO(n^2)ます。したがって、以下を結論付けることができます。

  • アルゴリズムにはO(ln n + n)環境の変更が含まれます(ステップ1 O(ln n)と靴下のすべてのペアを床から選ぶ)
  • アルゴリズムにはO(n^2)、ステップ2からの環境読み取りが含まれます。
  • アルゴリズムにはO(n^2)、手順2で靴下を別の靴下と比較するための論理演算および算術演算が含まれます。

したがって、適度な量の靴下の場合、環境の読み取り操作と環境の書き込み操作のそれぞれの要因であるO(r*n^2 + w*(ln n + n))場所rと実行時の全体的な複雑さがw発生します。論理演算と算術演算のコストは省略されています。これは、2つの靴下が同じペアに属しているかどうかを判断するために一定量の論理演算と算術演算が必要になるためです。これは、すべてのシナリオで実行できるとは限りません。


1
これは、stackoverflow.com / a / 14423956およびstackoverflow.com/a/14468913と同じだと思います。
Will Ness、

@WillNessうん、もう少し説明付き
SpaceTrucker

12
List<Sock> UnSearchedSocks = getAllSocks();
List<Sock> UnMatchedSocks = new list<Sock>();
List<PairOfSocks> PairedSocks = new list<PairOfSocks>();

foreach (Sock newSock in UnsearchedSocks)
{
  Sock MatchedSock = null;
  foreach(Sock UnmatchedSock in UnmatchedSocks)
  {
    if (UnmatchedSock.isPairOf(newSock))
    {
      MatchedSock = UnmatchedSock;
      break;
    }
  }
  if (MatchedSock != null)
  {
    UnmatchedSocks.remove(MatchedSock);
    PairedSocks.Add(new PairOfSocks(MatchedSock, NewSock));
  }
  else
  {
    UnmatchedSocks.Add(NewSock);
  }
}

12

操作が少なく、時間の消費も少ないという別の解決策を考え出しましたが、膨大な一連の靴下ペアリングで時間の消費を減らすのに十分なヒューリスティックであるかどうかを確認する必要があります。

前提条件: 同じ靴下があることを保証するものではありません。同じ色の場合でも、サイズやパターンが同じであるとは限りません。靴下はランダムにシャッフルされます。靴下の数が奇数である可能性があります(いくつかは足りない、私たちは何枚かわかりません)。変数「インデックス」を覚えて、0に設定する準備をします。

結果は1つまたは2つのパイルになります。1。「一致」と2.「欠落」

ヒューリスティック:

  1. 最も特徴的な靴下を見つけます。
  2. その一致を見つけます。
  3. 一致しない場合は、「不足している」山に置きます。
  4. 最も特徴的な靴下がなくなるまで、1から繰り返します。
  5. 靴下が6つ以下の場合は、11に進みます。
  6. すべての靴下を隣人に盲目的にペアリングする(パックしないでください)
  7. すべての一致したペアを見つけてパックし、パックしたペアを「一致した」パイルに移動します。新しい一致がない場合-「インデックス」を1増やします
  8. 「インデックス」が2より大きい場合(靴下の数が多いほど、盲目的にペアリングする可能性が低いため、これは靴下の数に依存する値になる可能性があります)11に進みます。
  9. 残りをシャッフルする
  10. 1に移動
  11. 「インデックス」を忘れる
  12. 靴下を選ぶ
  13. そのペアを見つける
  14. 靴下のペアがない場合は、「足りない」山に移動します
  15. 一致が見つかった場合はペアにして、ペアをパックして「一致した」パイルに移動します
  16. それでも足りない場合は、靴下を1つ12にします
  17. あと1つしかない場合は14に進みます。
  18. 笑って満足:)

また、靴下が損傷していないかどうかを確認することもできます。2から3、13から14の間に挿入できます。

どんな経験や修正についても聞くのを楽しみにしています。


これを書いた後は毎回使っています。それは私がもう少し効率的になるのを助け、仕事は今退屈ではなくなりました。
Sasa

11

靴下を並べ替えるとき、おおよその基数の並べ替えを行います、同じ色/パターンタイプの他の靴下の近くに靴下を落とします。靴下をドロップしようとしている場所またはその近くで完全一致が見られる場合を除いて、その時点でペアを抽出します。

他のほとんどすべてのアルゴリズム(usrによる上位スコアの回答を含む)は、ソートしてからペアを削除します。人間としては、一度に考慮される靴下の数を最小限に抑える方が良いと私は思います。

私はこれを次のように行います:

  1. 特徴的な靴下を選ぶ(何よりもまず最初に目を引くもの)。
  2. その概念的な場所から基数ソートを開始するには、その類似性に基づいてパイルから靴下を引っ張ります。
  3. 新しい靴下を現在の山の近くに置き、距離に応じて距離を置きます。靴下が同じであるために靴下を別の靴下の上に置いていることに気付いた場合は、そこで靴下のペアを形成し、それらを取り外します。これは、将来の比較で正しい場所を見つけるための労力が少なくなることを意味します。

これは、O(1)時間でファジーマッチする人間の能力を利用します。これは、コンピューティングデバイスでのハッシュマップの確立といくらか同等です。

特徴的な靴下を最初に引っ張ることにより、最初は特徴的ではない機能に「ズームイン」するためのスペースを残します。

蛍光色、縞模様の靴下、3組の長い靴下を削除すると、ほとんどが白い靴下になり、着用方法で大まかに分類されます。

ある時点で、靴下の違いは他の人がその違いに気付かないほど小さく、それ以上のマッチング作業は必要ありません。


10

靴下を手に取るときは、必ず1か所に置いてください。次に、次に取り上げる靴下。最初の靴下と一致しない場合は、最初の靴下の横に置きます。もしそうなら、ペアがあります。この方法では、実際に組み合わせの数は重要ではなく、靴下を1つ選択する可能性は2つしかありません。靴下の配列にすでに一致している場合と一致していない場合のどちらかです。つまり、配列内の場所に追加します。

これはまた、ソックスが一致すると削除されるため、配列内にすべてのソックスが存在することはほぼ確実です。


これが私がすることです... O(n)
Pykler '20

2
@Pykler-最良の場合はO(n)、最悪の場合はO(n * n)です。
Vilx-2013年

2
あなたがすでに見たすべての靴下の中で完全にユニークなハッシュを作成することができないと仮定すると、これは私にとって、以前に見た、一致するハッシュを
Pykler

10

サイズ「N」のハッシュテーブルを考えます。

正規分布を仮定すると、1つのバケットに少なくとも1つの靴下がマップされる「挿入」の推定数はNlogNです(つまり、すべてのバケットがいっぱいです)。

私はこれを別のパズルの一部として導出しましたが、間違っていることが証明されて嬉しいです。 これは私の同じブログ記事です

あなたが持っている靴下のユニークな色/パターンの数の数のおおよその上限に「N」を対応させてください。

衝突(別名:一致)が発生したら、その靴下のペアを削除するだけです。NlogNソックスの次のバッチで同じ実験を繰り返します。それの美しさは、人間の心の働き方のせいで、NlogN並列比較(衝突解決)ができることです。:-)


10

ソックスは、実際のものでも、類似のデータ構造でも、ペアで提供されます。

最も簡単な答えは、ペアを分離できるようにする前です。ペアの単一のデータ構造が初期化されており、左右の靴下へのポインタが含まれているため、靴下を直接またはペアを介して参照できます。靴下は、そのパートナーへのポインタを含むように拡張することもできます。

これは、抽象化の層でそれを削除することにより、計算ペアリングの問題を解決します。

同じ考えを靴下のペアリングの実際的な問題に適用すると、明らかな答えは、靴下のペアリングを解除しないことです。靴下はペアで提供され、ペアで引き出しに入れて(おそらくそれらを一緒にボールに入れて)、ペアで着用します。ただし、ペアリングを解除できるのは洗濯機内にあるため、必要なのは靴下をまとめて効率的に洗浄できる物理的なメカニズムだけです。

2つの物理的な可能性があります。

各靴下へのポインターを保持する「ペア」オブジェクトの場合、靴下をまとめるために使用する布製バッグを用意できます。これは大きなオーバーヘッドのようです。

しかし、それぞれの靴下が他方への参照を維持するために、次のようなきちんとした解決策があります:ポッパー(または、アメリカ人の場合は「スナップボタン」):

http://www.aliexpress.com/compare/compare-invisible-snap-buttons.html

次に、靴下を脱いで洗濯かごに入れたらすぐに靴下をはめ込み、靴下を「ペア」の概念の物理的な抽象化とペアにする必要があるという問題を取り除きました。


すでにペアになっているデータを扱うのは簡単なので、質問には答えません。データがペアになっておらず、ペアにしたいときにどうするかが問題です。
2015年

8

「移動」操作がかなり高価で、「比較」操作が安価であり、とにかくセット全体を元のストレージよりもはるかに高速なバッファに移動する必要がある場合...ソートを必須に統合するだけ移動します。

選別のプロセスを吊り下げて乾かすことを統合すると、それが簡単になります。とにかく各靴下を手に取り、それを吊るす(移動する)必要があります。紐の特定の場所に吊るすのに何もかかりません。バッファ全体(文字列)の検索を強制しないために、靴下を色/濃淡で配置することを選択します。左が暗い、右が明るい、色鮮やかなフロントなど。靴下を掛ける前に、一致する靴下がすでにある場合は「右側」を確認します。これにより、「スキャン」が他の2〜3靴下に制限されます。 、私はその隣にもう1つを掛けます。それから私は、乾いたときに紐から外しながらペアにそれらをロールバックします。

これは、トップアンサーで提案されている「色によるパイルの形成」とそれほど異なるようには見えないかもしれませんが、最初に、個別のパイルではなく範囲を選択することで、「紫」が「赤」または「青」のパイルになるかどうかを問題なく分類できます。それはちょうど間にあります。そして、2つの操作を統合することにより(ハングして乾燥してソートする)、ハングしている間のソートのオーバーヘッドは、個別のソートの場合の10%のようになります。


このアプローチには他に2つの利点があります。ライン乾燥は、タンブル乾燥機よりも靴下IMEの損失がはるかに少なく、ソートプロセスを残りの洗濯物に拡張できるため、たとえば、すべてのタオルが互いに近くにあり、折りたたむことができます。ラインとビニングされ、彼らのストレージに直接運ばれました。また、2つのローエフォートパスで機能し、服を上げてから再び降ろします。
cphlewis 2015

8

私は靴下のペアリングを完了しました、そしてそれを行うための最良の方法は次のとおりであることがわかりました:

  • 靴下の1つを選択してそれを片付けます(そのペアの「バケット」を作成します)
  • 次のものが前のもののペアである場合、それを既存のバケットに入れ、そうでなければ新しいものを作成します。

最悪の場合、n / 2の異なるバケットがあり、どのバケットに現在の靴下のペアが含まれるかについてn-2の決定があることを意味します。明らかに、このアルゴリズムは、ペアが数個しかない場合にうまく機能します。12組でやった。

それはそれほど科学的ではありませんが、うまくいきます:)


新しい靴下を引き出すたびに各バケットを反復処理する必要があるため、これはまだO(n ^ 2)アルゴリズムです。しかし、同じバッチ内で購入した靴下でさえ、それらを効果的にペアユニーク(またはシングルユニーク)にするわずかな違いがあるという事実を考慮すると、とにかく良い方法はありません
Semisonic

同意しますが、私のアルゴリズムは人間がペアリングを行っていることを前提としています。したがって、一致するバケットを検索するときには、一種のキャッシュが頭に浮かぶので、実際にバケットを反復処理する必要はありません。ペアリング中に私の頭の中でこのキャッシュメカニズムのためにどのようなデータ構造が構築されているのかわかりません。
maestro 2018年

8

私のソリューションは正式に必要なので、要件に正確に対応していません O(n)「余分な」スペースを。しかし、私の条件を考慮すると、実際のアプリケーションでは非常に効率的です。だから面白いと思います。

他のタスクと組み合わせる

私の場合の特別な条件は、乾燥機を使用せず、通常の布乾燥機に布を掛けるだけです。布を吊るすにはO(n)操作が必要です(ちなみに、私は常に箱詰めを検討しています問題をます)。その性質上、問題は線形の「余分な」スペースを必要とします。バケツから新しい靴下を取り出すとき、ペアがすでにハングしている場合は、ペアの隣にそれを掛けてみます。新しい靴下の靴下の場合、その隣にスペースを残します。

Oracle Machineの方が優れています;-)

一致する靴下がすでにどこかにぶら下がっているかどうかを確認するために、いくつかの追加の作業が明らかに必要であり、それはコンピューターのO(n^2)係数を使用してソリューションをレンダリング1/2します。しかし、この場合、「ヒューマンファクター」は実際には利点です。O(1)一致する靴下がすでにハングしている場合は、(ほとんどの場合)非常に迅速に(ほぼ)識別することができます(おそらく、知覚できない脳内キャッシングが関係しています)。Oracle Machineのように限定された「オラクル」;-)私たち人間は、場合によってはデジタルマシンに比べてこれらの利点があります;-)

もう少しでO(n)

したがって、ソックスのペアリングの問題と吊り布の問題を結びつけると、O(n)「余分なスペース」が無料で得られます。解決策はほぼO(n)間に合い、単純な吊り布より少しだけ多くの作業が必要で、すぐに完全なペアにアクセスできます。非常に悪い月曜日の朝でも靴下... ;-)


8

私はこの問題に新しい何かを貢献できることを望みます。洗濯の全体的なパフォーマンスを低下させることなく、前処理を実行できる点が2つあるという事実はすべての回答で無視されていることに気付きました。

また、大家族の場合でも、靴下を多数想定する必要はありません。靴下は引き出しから取り出されて着用され、洗濯される前にとどまる場所(おそらくビン)に投げられます。私は言ったビンをLIFOスタックとは呼ばないでしょうが、

  1. 両方の靴下を箱のほぼ同じ場所で投げます
  2. ビンはどの時点でもランダム化されないため、
  3. このビンの上部から取得したサブセットには、通常、ペアの靴下が両方含まれています。

私が知っているすべての洗濯機はサイズが限られているため(洗う必要のある靴下の数に関係なく)、実際のランダム化は洗濯機で行われます。靴下の数に関係なく、ほとんど含まれていない小さなサブセットがあります。シングルトン。

私たちの前処理の2つの段階は、「洗濯物を靴下に置く」と「洗濯物から靴下を取り出す」ことです。これは、清潔であるだけでなく乾燥した靴下を手に入れるために必要です。洗濯機と同じように、物干し用ロープは有限であり、靴下を置くライン全体が見えると思います。

put_socks_on_line()のアルゴリズムは次のとおりです。

while (socks left in basket) {
 take_sock();
 if (cluster of similar socks is present) { 
   Add sock to cluster (if possible, next to the matching pair)
 } else {
  Hang it somewhere on the line, this is now a new cluster of similar-looking socks.      
  Leave enough space around this sock to add other socks later on 
 }
}

ソックスを移動したり、最適なマッチを探したりするのに時間を無駄にしないでください。これはすべてO(n)で行う必要があります。これは、並べ替えずにラインに配置するだけでも必要です。靴下はまだペアになっておらず、ライン上にはいくつかの類似クラスターしかありません。靴下のセットが限られていると便利です。これは、「良い」クラスタを作成するのに役立ちます(たとえば、靴下のセットに黒い靴下しかない場合、色でクラスタリングするのは適切ではありません)。

take_socks_from_line()のアルゴリズムは次のとおりです。

while(socks left on line) {
 take_next_sock();
 if (matching pair visible on line or in basket) {
   Take it as well, pair 'em and put 'em away
 } else {
   put the sock in the basket
 }

残りのステップの速度を向上させるために、次の靴下を無作為に選ぶのではなく、各クラスターから靴下の後に順次靴下を取ることが賢明であることを指摘しておきます。どちらの前処理ステップでも、靴下をラインまたはバスケットに入れるだけで、何もしなくて済むので、洗濯のパフォーマンスが大幅に向上します。

この後、ハッシュ分割アルゴリズムを実行するのは簡単です。通常、ソックスの約75%は既にペアリングされており、ソックスの非常に小さなサブセットが残っています。このサブセットはすでに(ある程度)クラスター化されています(前処理ステップの後でバスケットにエントロピーをあまり導入していません)。もう1つは、残りのクラスターは一度に処理できるほど小さい傾向があるため、クラスター全体をバスケットから取り出すことができるということです。

sort_remaining_clusters()のアルゴリズムは次のとおりです。

while(clusters present in basket) {
  Take out the cluster and spread it
  Process it immediately
  Leave remaining socks where they are
}

その後、靴下は残りわずかです。これは、以前にペアになっていない靴下をシステムに導入し、特別なアルゴリズムなしで残りの靴下を処理する場所です。残りの靴下は非常に少なく、視覚的に非常に高速に処理できます。

残りのすべての靴下について、私はそれらの対応するものがまだ洗っていないと想定し、次の反復のためにそれらを保管します。ペアになっていない靴下の増加を登録した場合(「靴下の漏れ」)、ビンを確認する必要があります-ランダム化される可能性があります(眠っている猫はいますか?)

これらのアルゴリズムには多くの仮定があることを知っています。ある種のLIFOスタックとして機能するビン、制限された通常の洗濯機、制限された通常の物干しロープ-これは依然として非常に多くの靴下で機能します。

並列処理について:両方の靴下を同じ箱に捨てる限り、これらすべての手順を簡単に並列化できます。


靴下は、一部のデータベースで任意のオブジェクトをペアリングするための単なる比喩です。
2015年

1
了解しました。あなたが著者であることを確認できませんでした。一般的なソリューションが必要な場合は、本当にそうすべきでした。とにかく、一般的なソリューションを考え出さなければならない場合を除いて、考慮している情報を考慮することは何の問題もありません。ソリューションの再利用性を放棄すると、パフォーマンスが大幅に向上します。この場合、ユースケースと利用可能なデータベース全体を考慮することは有益です。ただし、あなたの特別な質問に対するこの特別な回答には、サイズの異なる黒い靴下など、見た目が似ている靴下に問題があるため、適用できない場合があります。
Philipp Flenker、2015年

1
また、データベース内の任意のオブジェクトのペアリングについて質問したため、2kを超える賛成票は得られませんでした。あなたは靴下の本質(データとは対照的に複製することはできません)のために質問を具体的に制約し、靴下と配偶者の靴下を簡単に区別できるという事実を使用することを奨励しました。靴下について質問する場合、回答がデータベースに関するものであると期待しないでください;-)
Philipp Flenker

1
いくつかの仮定があります:通常の洗濯機、通常の洗濯物、および両方の靴下を箱に同時に投げるという事実、つまりほとんどの場合、両方の靴下が同じマシンにあること、およびしたがって、ソートされる残りの靴下は小さいです。しかし、データベースに任意のオブジェクトを保存することについての答えが本当に必要だったので、私のソリューションについてさらに議論することは本当に役に立ちますか?
Philipp Flenker、2015年

1
先ほどお話ししたように、他の人から回答された要素の明確性の問題を除いて、あなたが求めたすべての問題に対処したと思います。私はここでdoucheになるつもりはありませんが、私はしばらく前にこの回答に多くの労力を費やしましたが、あなたが今いくつかの回答を調べ、元の質問に回答しなかったと主張することは少し失望しています。スレッド全体をそのままにしておきませんか。質問してから2年以上経っても、興味深い読み物です。
Philipp Flenker、2015年

8

私はO(1)時間を要するプロセスに私の労力を減らすために簡単な手順を踏みました。

入力を2種類の靴下(レクリエーション用の白い靴下、仕事用の黒い靴下)の1つに減らすことで、手に持っている2つの靴下のどちらかを決定するだけで済みます。(技術的には、これらが一緒に洗浄されることはないため、プロセスをO(0)時間に短縮しました。)

望ましい靴下を見つけ、既存の靴下の必要性をなくすために十分な量を購入するには、いくらかの事前の努力が必要です。黒い靴下が必要になる前にこれを行ったので、私の努力は最小限でしたが、走行距離は異なる場合があります。

このような先行的な取り組みは、非常に人気があり効果的なコードで何度も見られます。例には、パイをいくつかの小数に#DEFINEすることが含まれます(他の例が存在しますが、それは今頭に浮かぶものです)。


7

パターンをハッシュとして使用して、一致しない靴下に使用されるハッシュテーブルを作成します。靴下を1つずつ繰り返します。靴下のハッシュテーブルでパターンが一致する場合は、靴下をテーブルから取り出し、ペアを作成します。靴下が一致しない場合は、テーブルに入れます。


質問で具体的に言及されているように、インプレースではない方法は?
2015年

7

n組の靴下を並べ替える問題はO(n)です。それらを洗濯かごに入れる前に、左のものを右のものに通します。それらを取り出したら、糸を切り、各ペアを引き出しに入れます-nペアで2回の操作なので、O(n)。

次の問題は、あなたが自分で洗濯をし、妻が自分で洗濯するかどうかです。これは、まったく別の問題領域で起こりそうな問題です。:)


これは、靴下が単なる比喩であるという質問には答えません。
2015年

問題は、ペアになっていないパイルから靴下をペアリングする方法であり、ペアリングする必要を回避する方法ではありませんでした。
2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.