如何有效地将袜子配对?


3911

昨天我从干净的洗衣店里给袜子配对,发现我做这件事的方式不是很有效。我一直在天真地搜寻-挑选一只袜子,然后“反复”寻找那双袜子。这需要遍历的n / 2 * N / 4 = N 2平均/ 8的袜子。

作为计算机科学家,我在想我能做什么?当然会想到进行排序(根据大小/颜色/ ...)以实现O(NlogN)解决方案。

不能选择散列或其他非现场解决方案,因为我无法复制袜子(尽管如果可以的话,可能会很好)。

因此,问题基本上是:

给定一堆n袜子,其中包含2n元素(假设每只袜子都具有一对完全匹配的袜子),最好的方法是将它们有效配对并具有对数的额外空间?(我相信我可以记住该信息的数量,如果需要的话。)

我希望能从以下几个方面回答这个问题:

  • 大量袜子的一般理论解决方案。
  • 袜子的实际数量不是很大,我不相信我的配偶和我有超过30对。(而且很容易区分我的袜子和她的袜子;也可以使用吗?)
  • 它等同于元素区分性问题吗?

448
我使用鸽子孔原理将洗衣堆中的一对准确配对。我有3种不同颜色的袜子(红色,蓝色和绿色),每种颜色2对。每次我都会捡起四只袜子,我总是会结成一双然后开始工作。
斯里尼瓦斯

59
另一种鸽子洞原则:如果您选择n / 2 +1袜子的子集,则该子集中必须至少有一对。
wildplasser 2013年

40
好问题!你可能有兴趣在我的相关问题的文章,这是拉动两个匹配的袜子了桩的可能性的讨论:blogs.msdn.com/b/ericlippert/archive/2010/03/22/...
埃里克利珀特

335
为什么不产卵一个孩子,waitpid以致作为父母,您甚至自己都没有整理袜子?
Mxyk 2013年

137
我只穿着白色及膝袜解决了这个问题。他们都匹配。我可以简单地从堆中随机抓取任意两只袜子,它们会匹配。通过不配对袜子,我进一步简化了问题。我有一个袜子抽屉,我把所有袜子都放进去了,没有配对。我每天早上从抽屉里随机地抓两个。我将其简化为O(0)。没有比这更简单的了。:)

Answers:


2448

已经提出了排序解决方案,但是排序有点过多:我们不需要定单;我们只需要平等团体

因此散列就足够了(并且更快)。

  1. 对于每种颜色的袜子,形成一堆。遍历输入筐中的所有袜子并将它们分配到颜色堆上
  2. 遍历每个桩,并按其他度量(例如图案)将其分配到第二组桩中
  3. 递归应用此方案,直到将所有袜子分配到很小的绒头上,然后即可立即进行视觉处理

当需要对大型数据集进行哈希联接或哈希聚合时,这种递归哈希分区实际上是由SQL Server完成的。它将其构建输入流分配到许多独立的分区中。此方案可线性扩展到任意数量的数据和多个CPU。

如果您可以找到一个提供足够存储桶的分发密钥(哈希密钥),而每个存储桶足够小,可以非常快速地进行处理,则不需要递归分区。不幸的是,我认为袜子没有这种特性。

如果每个袜子都有一个称为“ PairID”的整数,则可以根据PairID % 10(最后一位)轻松地将它们分配到10个存储桶中。

我能想到的最好的现实分区是创建一个矩形的矩形堆:一个维是颜色,另一个维是图案。为什么是矩形?因为我们需要O(1)对堆的随机访问。(3D 长方体也可以,但这不是很实际。)


更新:

那么并行性呢?可以让多个人更快地匹配袜子吗?

  1. 最简单的并行化策略是让多名工人从输入筐中取出并将袜子放在堆上。这只能扩展得如此之多-想象有100个人在战斗10堆。同步成本(表现为手工冲突和人际交往)破坏了效率和速度(请参阅《通用可扩展性法则》!)。这容易陷入僵局吗?否,因为每个工人一次只需要访问一堆。只有一个“锁”就不会出现死锁。取决于人类如何协调对堆的访问,可能会出现活锁。他们可能只是使用随机退避就像网卡在物理级别上所做的那样,以确定哪些卡可以独占访问网络线路。如果它适用于NIC,它也应适用于人类。
  2. 如果每个工人都有自己的桩,它几乎可以无限扩展。然后,工人可以从输入筐中取出大块的袜子(很少有竞争,因为他们很少这样做),并且在分配袜子时根本不需要同步(因为他们有局部线程堆)。最后,所有工人都需要结合他们的桩具。我相信,如果工人形成一个聚集树,可以用O(log(工人数*每个工人的堆数))来完成。

怎么样的元素明显的问题?如文章所述,可以在中解决元素差异性问题O(N)。袜子问题也是O(N)如此(同样,如果只需要一个分配步骤(我提议多个步骤只是因为人类在计算上很差-如果分配在一个步骤上就足够了md5(color, length, pattern, ...),即所有属性的完美哈希))。

显然,没有人能比快O(N),因此我们已经达到了最佳下限

尽管输出并不完全相同(在一种情况下,只是布尔值。在另一种情况下,是成对的袜子),则渐进复杂度是相同的。


72
这正是我的工作!我根据袜子的开口样式(我只有白色)来堆放东西,这给了我足够的“桶”以快速匹配每个袜子。
Scott Chamberlain 2013年

29
我已经用袜子试过了(我已经轻松穿了30多双了),可这真是快。我发现的一个问题是,当我没有足够好的哈希算法(我有很多没有任何图案的白袜子)时,它变得很困难。在这种情况下,最佳的做法是什么?
NothingsIm不可能

56
@NothingsImpossible,这就是一个糟糕的Web服务器的哈希冲突攻击的感觉!白袜子是否可以通过某些属性来区分?必须有可以分发它们的东西。否则,您可以随意形成一对。
usr

37
这是基数排序,我同意这是正确的答案。@MarkPeters我认为您不需要查找表。袜子上的一次线性传递可以将袜子转换为数字向量,从而使“袜子段”到铲斗的映射变得微不足道。袜子可以用绳子绑在向量上,这样一来您就不需要在最后再进行一次线性传递了。
Pointy 2013年

49
我上大学的一个人实际上有PairID。它被缝在每双袜子上,分别是:1,2,3,4 ...
Ryan Lundy 2013年

579

由于人脑的体系结构与现代CPU完全不同,因此这个问题没有实际意义。

人们可以使用“找到匹配对”对于一个不太大的集合进行一项操作,从而胜过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);
}

至少这是我在现实生活中使用的,并且我发现它非常有效。缺点是它需要一个平坦的表面,但通常足够。


228
随着袜子数量的增加,人的SIMD变得不比CPU好。
Lie Ryan

25
最好的答案,IMO。虽然将日常问题简化为一种计算机算法既有趣又聪明(并且很适合SO),但使用人眼/大脑的分辨力来处理大约60只袜子的感觉更为有意义。
drug_user841417

13
@LieRyan如果袜子是均匀分布的,由于生日的悖论(除非您可以区分颜色达到任意精度,否则我会怀疑),最终您会注意到这对袜子在任何足够小的袜子中都不会出现。人类的色彩匹配算法,而是扩展步骤。
托马斯

13
@ dpc.ucore.info不,因为它们具有不同的编织袖口样式,袖口长度,整体长度和黑色阴影(对于我的最后一个,我妻子可能会对我造成身体伤害)。
基督教徒

199
您最好希望您的袜子数是偶数,否则您将要折叠袜子很长时间……
Patrick James McDougle13年

258

情况1:所有袜子都是一样的(顺便说一句,这是我在现实生活中所做的)。

选择其中任意两个配对。恒定的时间。

情况2:组合数量不变(所有权,颜色,大小,纹理等)。

使用基数排序。这只是线性时间,因为不需要比较。

情况3:事先不知道组合的数量(一般情况)。

我们必须进行比较,以检查是否有两双袜子成对出现。选择一种O(n log n)基于比较的排序算法。

但是,在现实生活中,当袜子的数量相对较少(恒定)时,这些理论上最优的算法将无法正常工作。它可能比顺序搜索要花费更多的时间,而顺序搜索理论上需要二次时间。


8
>它可能比顺序搜索花费更多的时间,而顺序搜索理论上需要二次时间。是啊,这就是为什么我不喜欢这样做,也许我应该扔掉我所有的袜子,并用案例1.开始
尼尔斯

57
所有袜子相同的缺点是它们倾向于以不同的速度老化。因此,您仍然最终尝试根据它们的磨损程度来匹配它们。(这比简单地按模式匹配更难)
SDC 2013年

118
拥有60对相同的袜子的问题是“因为它使配对更容易”,这是给人的印象是您在计算机上工作。
史蒂夫·艾夫斯

13
情况1并非涉及某个操作(例如将对折叠在一起)的恒定时间。在这种情况下,它是线性时间,具有最小的常数因子(其证明留给读者练习)。一个人可能无法同时折叠一对和一桶装满袜子的袜子。但是,它线性缩放。根据阿姆达尔定律,它具有无限的加速,而忽略了开销。根据古斯塔夫森定律,您可以折叠尽可能多的对,而只要有足够的工人就可以折叠一对(折叠的数量留给读者练习),而无需理会开销。
2013年

7
@PauloMadeira排序是固定时间的-您只需将纸堆放在抽屉中即可。在这种情况下,唯一的操作实际上是将袜子放在脚上,这也是恒定的。通过延迟执行袜子的磨损可以获得性能,这可能会牺牲一些空间(未折叠袜子的消耗空间大于折叠空间)。我认为这是值得的;我通常和我的妻子失去这种争论。
特拉维斯

157

非算法答案,但在执行时却“有效”:

  • 步骤1)丢弃所有现有的袜子

  • 步骤2)前往沃尔玛(Walmart),以10包-白色n包和m黑色的包购买。日常生活中无需其他颜色。

但是有时候,我必须再次这样做(袜子丢失,袜子损坏等),而且我不想过多地丢弃完美的袜子(我希望他们继续出售相同的袜子参考!),所以最近我选择了一种不同的方法。

算法答案:

考虑一下,如果您像第二只袜子一样只抽出一只袜子,那么,在幼稚的搜索中找到匹配的袜子的几率很低。

  • 因此,随机挑选其中五个,并记住其形状或长度。

为什么是五个?通常,人类会记住在工作存储器中的五到七个不同的元素(有点像RPN堆栈的人类等效元素),五个是安全的默认值。

  • 从2n-5的堆栈中取出一个。

  • 现在,在您绘制的五个对象中寻找一个匹配项(视觉模式匹配-人类擅长于一小堆),如果找不到,则将其添加到您的五个中。

  • 保持从堆栈中随机挑选袜子,并与您的5 + 1袜子进行比较。随着堆栈的增加,它会降低性能,但会增加赔率。快多了。

随意写下公式来计算您必须为比赛的50%几率抽取多少个样本。IIRC这是一个超几何定律。

我每天早上都这样做,很少需要抽三张以上,但是我有n几双类似的m袜子(大约10双,丢掉或丢掉)。现在您可以估计我的股票数量了:-)

顺便说一句,我发现每次我需要一双袜子时对所有袜子进行分类的交易成本总和要比一次绑定袜子要少得多。即时作业会更好,因为这样您就不必束缚袜子了,边际收益也会递减(也就是说,当您在洗衣房中的某个地方并且需要时,您一直在寻找两三只袜子)完成与袜子的匹配,您会因此而浪费时间)。


25
支持“非算法”答案。这正是我所做的,而且效果很好。如果您通过将清洗过的袜子放在后面并从抽屉的前部拉出来“旋转”袜子,则替换问题就不成问题了。所有袜子均匀穿着。当我开始注意到其中的一些磨损时,我将其列入购物清单以完全替换整个袜子类别。对于旧袜子,我将最好的20%捐给Goodwill(绑在杂物袋中,这样它们就不会混在一起了),其余的都投了。您并没有浪费袜子,这时80%的人只剩下6个月了。
FastAl

2
顺便说一句(1)绑扎袜子会导致一根弹性的袜子被拉伸存储,并且袜子会更快地破裂。限制独特袜子的种类会使绑定变得无用。(2)限制独特袜子的缺点是,对于某些时尚人士而言,该方法可能不合适。
FastAl

3
我是专门来发布您的“非算法”答案的。就像真正的计算机科学一样,大多数人从未对数据及其结构给予足够的重视。
bkconrad

我每天早上都使用这种算法方法,它就像一个魅力!此外,我将破旧的袜子放到另一堆上,以备日后扔掉(不幸的是,他们设法在找到时间将其丢掉之前又重新回到了原来的袜子上)。
DonatasOlsevičius2013年

3
«n白色小包和m黑色小包。日常生活中不需要其他颜色»轻松选择袜子的一个好的标准规则实际上是它们应该与您的裤子的颜色或皮带的颜色匹配。因此,最常用的颜色可能是黑色,蓝色,灰色和一些棕色。很难相信一个人需要很多白袜子。
Andrea Lazzarotto 2015年

106

我要做的是拿起第一只袜子放下(例如,放在洗衣盆的边缘)。然后,我拿起另一只袜子,检查它是否与第一只袜子相同。如果是,我将它们都删除。如果不是,我把它放到第一只袜子的旁边。然后,我拿起第三只袜子,并将其与前两只袜子进行比较(如果它们仍在那儿)。等等。

假设“移除”袜子是一种选择,则可以很容易地在阵列中实施此方法。实际上,您甚至不需要“去除”袜子。如果不需要对袜子进行排序(请参阅下文),则只需将它们四处移动即可得到一个数组,该数组将所有袜子成对排列。

假设袜子的唯一操作是比较相等性,该算法基本上仍是n 2算法,尽管我不知道平均情况(从未学会过计算)。

排序当然可以提高效率,特别是在现实生活中,您可以轻松地在另外两只袜子之间“插入”袜子。在计算中,一棵树可以实现相同的目的,但这是额外的空间。而且,当然,我们又回到了NlogN(或者,如果有几只袜子的排序标准相同,但不是同一对袜子,则更多)。

除此之外,我什么也没想到,但是这种方法在现实生活中确实非常有效。:)


7
这也是我所做的事情(请注意,如果只留空格,则插入也是O(1)),但是从理论上讲,袜子的伸缩性很差。
Mooing Duck 2013年

15
理论上种类繁多的袜子可伸缩性差
Steven Lu

@StevenLu-正如我所说-是n * n或nLogn,具体取决于您是否对其进行排序。因此它的伸缩性与任何排序算法一样差。如果要更快,请给它们编号并使用基数排序。
Vilx-

这实际上是在基于哈希的查找中存储找到但不匹配的袜子。对于理想的哈希,它是O(n),但是如果存储的袜子足够多,哈希就开始退化,它就会变得更加复杂。
乔恩·汉纳

3
在另外2张袜子之间插入袜子对配对袜子的目标有什么价值?没有袜子的基数。:-x
JoeBrockhaus

60

这是在问一个错误的问题。正确的问题是,为什么我要花时间整理袜子?当您以所选的X个货币单位来评估您的空闲时间时,每年花费多少钱?

而且,这不仅是任何空闲时间,更是早上的空闲时间,您可能会在床上度过,或者喝着咖啡,或者早点离开,而不会被交通阻塞。

退后一步,想办法解决问题通常是很好的。

有办法!

找到你喜欢的袜子。考虑所有相关特征:不同照明条件下的颜色,整体质量和耐用性,不同气候条件下的舒适度以及气味吸收。同样重要的是,它们在储存时不应失去弹性,因此天然织物是不错的选择,并且应该采用塑料包装。

左脚袜子和右脚袜子之间最好没有差异,但这不是关键。如果袜子是左右对称的,则找到一对是O(1)运算,而对袜子进行排序则是近似O(M)运算,其中M是房屋中的位置数(最好是一些袜子)小常数。

如果您选择了左右袜子不同的花式对,则对左右脚桶进行完整的桶排序将取O(N + M),其中N是袜子的数量,M与上面的相同。其他人可以给出寻找第一个对的平均迭代的公式,但是用盲搜索找到对的最坏情况是N / 2 + 1,这对于合理的N来说在天文学上是不可能的情况。这可以通过使用高级图像来加快Mk1 Eyeball扫描一堆未分类的袜子时,识别算法和启发式算法。

因此,用于实现O(1)袜子配对效率(假设对称袜子)的算法为:

  1. 您需要估算一生中需要多少双袜子,或者直到您退休并转入温暖的气候,而无需再穿袜子。如果您还年轻,您还可以估计我们家中都需要有袜子分类机器人的时间,而整个问题就变得无关紧要了。

  2. 您需要了解如何批量订购选定的袜子,价格如何以及如何交付。

  3. 订购袜子!

  4. 摆脱旧袜子。

替代步骤3将涉及比较这些年来多年来一次购买几双相同数量或价格较便宜的袜子的成本,以及对袜子进行分类的成本,但请注意:批量购买更便宜!而且,存储袜子的价值会随着股票价格的上涨而增加,这比许多投资所能带来的收益还要多。再有,这也有存储成本,但是袜子确实并没有在壁橱的顶架上占用太多空间。

问题解决了。因此,只要知道自己在余生中每天都在节省金钱和时间,就可以买新袜子,扔掉/捐赠旧袜子并过上幸福的生活。


一生(假设75年)的袜子供应量(假设您每月消耗4对,即3600副)将占用(假设一双新袜子占用20立方英寸)总共1 1/2立方码。那是巨大的空间。假设他们在一个大约是立方体的盒子中将其运送给您,则该箱子的侧面大约3英尺4英寸。
AJMansfield

2
@AJMansfield有效的关注。但是,我不同意您的一些数字。我的时间跨度仅为40年(25 ... 65)(从不住在父母/宿舍/等到退休之间的时间,请参见上文)。另外,我认为一对在原包装中的尺寸更需要0,5x4x6英寸。这些数字使您的空间节省时间大大减少了!
海德

步骤4不必要地浪费了-1。
Dan Bechard

2
对于可能会因AJMansfield的测量结果而感到困惑的其他人的指南,转换为公制:»将占用(假设一双新袜子占用327cm³)总共1.14m³。那是巨大的空间。假设它们是在大约一个立方体的盒子中将其运送给您的,则该条板条箱的侧面大约为1.04 m。«
Joey

基于好奇心的问题如何成为“错误的问题”?经典StackOverflow ...
Timmmm '19

52

理论极限为O(n),因为您需要触摸每只袜子(除非有些袜子已经以某种方式配对)。

您可以使用基数排序实现O(n)。您只需要为存储桶选择一些属性即可。

  1. 首先,您可以选择(她的,我的)-将它们分成两堆,
  2. 然后使用颜色(颜色可以有任何顺序,例如按颜色名称的字母顺序)-按颜色将它们分成绒头(请记住,对于同一绒头中的所有袜子,请保持步骤1的初始顺序),
  3. 然后是袜子的长度
  4. 然后质地,....

如果您可以选择有限数量的属性,但是有足够的属性可以唯一地标识每对,则应该用O(k * n)表示,如果我们可以认为k是有限的,则为O(n)。


3
袜子通常以4包或更大的包装出售,因为这样更便宜,但这也使它们难以区分。为了解决这个问题,我的妻子在我购买的每双新袜子上都缝了一个小小的标记。如果标记用完了,则每对标记的颜色都不同,或者形状也不同。使用这种方法,您甚至不需要有限的属性集。只需在每对上缝制一个唯一的数字。:)对于加分项,请使用二进制。
Vilx-

29
@ Vilx-为什么?!?难道不是所有观点都没有区别吗?
flup

2
@flup-我认为重点是成批出售。:)对我来说,这有助于使它们成对磨损。否则,我最终会得到三只非常破旧的袜子和一只全新的袜子。有点傻
Vilx-

13
我不同意O(n)的计算。什么是$ k $?$ k $是属性的数量。我认为$ k $是$ O(log n)$,因为它必须足以唯一地标识每对。如果您有两对(黑白),那么颜色($ k = 1,n = 2 $)就足够了。如果您有一对黑色,则简短;一对黑色长;一对白色短 一对白色的长线,则$ k = 2,n = 4 $。然后,如果我们限制$ k $,我们将同时限制$ n $。如果我们要限制$ n $,则订单计算不再有意义。
emory

3
@emory,我认为您是在寻找反引号而不是$角色,以使您的内容看起来像代码一样。
Xymostech

33

作为实际的解决方案:

  1. 快速堆起容易区分的袜子。(按颜色说)
  2. 快速分类每堆,并使用袜子的长度进行比较。作为一个人,您可以做出一个相当快速的决定,以使用哪种袜子来进行分区以避免最坏的情况。(您可以同时看到多只袜子,利用它来发挥自己的优势!)
  3. 当它们达到阈值时停止对堆进行分类,在该阈值下您可以轻松找到斑点对和不可配对的袜子

如果您有1000只袜子,有8种颜色并且平均分配,则您可以在c * n时间内将每125只袜子分成4堆。使用5根袜子的阈值,您可以在6次跑步中对每堆进行分类。(用2秒钟的时间将袜子扔到正确的桩上,将花费您不到4小时的时间。)

如果您只有60只袜子,3种颜色和2种袜子(您自己/您的妻子的袜子),则可以在1次运行中对每堆10只袜子进行排序(再次阈值= 5)。(计算2秒将花费您2分钟)。

最初的存储桶排序将加快您的处理速度,因为它会及时将n个袜子分成k个存储桶,c*n这样您就不必做任何c*n*log(k)工作了。(不考虑阈值)。因此,您所做的所有n*c*(1 + log(k))工作都是如此,其中c是将袜子扔到一堆的时间。

相较于任何c*x*n + O(1)方法,这种方法都是有利的log(k) < x - 1


在计算机科学中,这可能会有所帮助:我们有n种东西的集合,它们的顺序(长度),以及等价关系(额外信息,例如袜子的颜色)。等价关系使我们可以对原始集合进行划分,并且在每个等价类中,我们的订单仍保持不变。事物到其对等类的映射可以在O(1)中完成,因此只需要O(n)就可以将每个项目分配给一个类。现在,我们已经使用了额外的信息,可以以任何方式对每个类进行排序。优点是数据集已经大大缩小了。

如果我们有多个等价关系->创建颜色桩,则该方法也可以嵌套,而不是在纹理上的每个桩分区内,在长度上进行排序。任何等价关系创建的分区都具有两个以上大小相等的元素,将带来比排序更快的速度(前提是我们可以直接将袜子分配给它的堆),并且排序可以在较小的数据集上快速发生。


3
人类的最佳化:我认为,作为人类,对于步骤2,您应该以大致升序对袜子进行调低处理,然后以越来越细的粒度重复进行直到分类为止,有点像贝壳排序。对于人类(视觉估计)而言,这比基于比较交换的方法要快得多。
AndrewC

28

您正在尝试解决错误的问题。

解决方案1:每次将脏袜子放在洗衣篮中时,都要打个小结。这样一来,您将无需在清洗后进行任何分类。可以将其视为在Mongo数据库中注册索引。未来需要做一些工作以节省一些CPU。

解决方案2:如果是冬天,则不必穿配套的袜子。我们是程序员。只要有效,就没人需要知道。

解决方案3:传播工作。您想异步执行这样一个复杂的CPU进程,而不阻塞UI。把那堆袜子塞进袋子里。仅在需要时寻找一对。这样,所需的工作量就不那么明显了。

希望这可以帮助!


5
将袜子(或任何衣服)打成结会降低洗衣机洗衣服的能力,并使解开衣服的难度更大。解决方案2使事务状态越长,维护就越困难;6个月后,当您需要两条黑色脚踝袜子搭配一条短裤和运动鞋一起穿着时,进行6个月的工作会使发现这对裤子处于相同状态(肮脏/清洁,类似穿着)的可能性大大降低。解决方案3较少“异步”,而更为直率的“懒惰”;在需要的时候做您需要做的最少工作。
KeithS

回复:解决方案2:人们会知道我没有穿匹配的袜子,因为他们会在我的Birks中看到它们:)
Bob Probst,

@BobProbst是的,但是您的同行程序员也将与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”和“将s加到N”。跟踪到目前为止我们所看到的东西有多昂贵?

人类将使用各种策略来实现这些目标。人的记忆关联的,类似于哈希表,其中存储的值的特征集与相应的值本身配对。例如,“红色汽车”的概念映射到一个人能够记住的所有红色汽车。具有完美记忆的人具有完美的映射。大多数人在这方面(以及其他大多数人)并不完美。关联地图的容量有限。映射可能会崩溃 在各种情况下都不存在(一杯啤酒过多),被错误记录(“我虽然她的名字叫贝蒂,而不是内蒂”),或者即使我们观察到真相已经改变也永远不会被覆盖(“爸爸的车”唤起了当我们实际上知道他用红色的Camaro换成了“橙色的火鸟”时。

就袜子而言,完美的召回意味着看着袜子s总是能记忆其兄弟姐妹t,包括足够的信息(在熨衣板上的信息)可以t在恒定时间内定位。具有照片记忆的人可以在恒定时间内无故障地完成1和2的工作。

记忆力不佳的人可能会根据其能力范围内的特征使用一些常识对等类:大小(爸爸,妈妈,婴儿),颜色(偏绿色,偏红色等),图案(菱形,浅色等) ,样式(橄榄球,膝盖高等)。因此,熨衣板将分为几部分。通常,这可以通过内存在恒定的时间内定位类别,但是随后需要对类别“存储桶”进行线性搜索。

完全没有记忆力或想象力的人(对不起)只会将袜子放在一堆中,并对整个堆进行线性搜索。

有人建议,整齐的怪胎可能会使用数字标签对。这为总排序打开了方便之门,使人们可以使用与CPU可能完全相同的算法:二进制搜索,树,哈希等。

因此,“最佳”算法取决于运行它的湿件/硬件/软件的质量,以及我们对成对施加总订单的“作弊”意愿。当然,“最佳” 算法是雇用世界上最好的袜子分类器:一个人或机器,可以通过恒定的时间查找,插入,获取,快速存储大量N个袜子属性集到1-1关联内存中,并删除。这样的人和机器都可以采购。如果您有一只袜子,则可以在O(N)时间内将所有袜子配对N对,这是最佳选择。总订单标签使您可以使用标准哈希来与人机或硬件计算机获得相同的结果。


好的,这更好,尽管还是很错的。。。这个问题不是关于这个的。无论“ Church-Turing”论题是否正确,人类和我们的计算机都可以对袜子进行分类。(现实是,人类是高度有限的实体,其计算能力远低于Turing Machines……我们的计算机也是如此,但局限性有所不同。)
Jim Balter

我不同意。当然,我们当前使用的任何计算机本质上都是巨大的DFA(模数I / O差异),而不是TM。但是,任何模拟设备,例如我们的身体,都可以模拟无限大的磁带。我们还没有一个有用的方法来描述我们的思维方式。
基因

没有用于人类或其他物理设备的无限磁带,因为人脑中没有任何物体具有无限分辨率,也不可能具有无限分辨率。这也将有助于学习一些神经科学。无论如何,无论您想注入什么,这里都没有深层的哲学问题。但是,请相信您会……在这不是进行此类辩论的地方,而我之前已经讨论了太多次了。但是,我总是对那些几乎无法解决最简单问题(就是我们所有人)的人们感到高兴,他们认为它们与TM等效。
吉姆·巴尔特

22

成本:运动袜->高,排队寻找/搜索袜->小

我们要做的是减少移动次数,并补偿搜索次数。此外,我们可以利用智人的多用途环境在决策缓存中保存更多内容。

X =您的,Y =您的配偶

从所有袜子的A堆中:

挑选两只袜子,将对应的X袜子放在X线,将Y袜子放在Y线的下一个可用位置。

直到A为空为止。

对于每行X和Y

  1. 在行中选择第一个袜子,沿着该行搜索,直到找到相应的袜子。

  2. 放入相应的袜子成品线。

  3. 可选在搜索线时,并且您正在查看的当前袜子与前面的袜子相同,请对这些袜子执行步骤2。

(可选)在第一步中,您从该行中选择两个而不是两个,因为高速缓存内存足够大,我们可以快速确定其中一个与您正在观察的行中的当前袜子是否匹配。如果您幸运地拥有三只手臂,考虑到对象的内存足够大,则可以同时解析三只袜子。

直到X和Y都为空为止。

完成了

但是,由于它具有与选择排序类似的复杂性,因此由于I / O(移动袜子)和搜索(在袜子中搜索线)的速度而花费的时间要少得多。


22

这是基于比较的模型中的Omega(n log n)下界。(唯一有效的操作是比较两只袜子。)

假设您知道您的2n袜子是这样排列的:

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

其中f是集合{1,2,...,n}的未知置换。知道这一点不会使问题变得更难。有n!可能的输出(上半年和下半年之间的匹配),这意味着您需要log(n!)= Omega(n log n)比较。这可以通过排序获得。

由于您对与元素唯一性问题有关的连接感兴趣:证明针对元素唯一性的Omega(n log n)绑定比较困难,因为输出是二进制的yes / no。这里,输出必须是匹配的,并且可能的输出数量足以获得合理的界限。但是,存在与元素唯一性相关的变体。假设您给了2n只袜子,想知道它们是否可以唯一配对。您可以通过将(a 1,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个人袜子),我实际上就是这样做的:

  • 从堆中随机拿起袜子。
  • 对于第一只袜子,或者如果所有先前选择的袜子都已配对,只需将袜子放入未配对袜子“阵列”的第一个“插槽”中,就在您的面前。
  • 如果您选择了一只或多只未配对的袜子,请对照阵列中所有未配对的袜子检查您当前的袜子。
    • 在构建阵列时,可以将袜子分为一般类别或类型(白色/黑色,脚踝/船员,运动/着装),并且可以“向下钻取”以仅按比例进行比较。
    • 如果找到可以接受的匹配项,请将两只袜子放在一起,然后从阵列中将它们删除。
    • 如果不这样做,请将当前的袜子放入阵列中的第一个开放插槽中。
  • 重复每只袜子。

该方案最坏的情况是每对袜子都足够不同,必须完全匹配,并且您选择的前n / 2袜子都不同。这是您的O(n 2)情况,这不可能。如果唯一类型的袜子的数量t小于对数p = n / 2,并且每种类型的袜子都足够相似(通常以磨损相关的术语),则该类型的任何袜子都可以与任何袜子配对其他的,那么就像我上面推断,你永远不会有比较袜子的最大数量是牛逼,在此之后,下一个你拉的意志匹配其中一只未配对的袜子。与最坏情况相比,这种情况在普通袜子抽屉中更可能发生,并将最坏情况的复杂性降低为O(n * t),其中通常t << n


1
这可能很接近我的思维过程。我还有一个预排序优化的附加层。我的运动袜被白色清洗了,我的穿袜被颜色清洗了。这意味着只要我不将两堆衣物一起倒放,我的袜子就已经按类型分组了。白色负载的速度非常快(许多相同的袜子),但是正装袜子需要更长的时间。其他关键提示-为排序提供更多可用的内存(先折叠并删除所有非袜子,然后运行配对算法)
orh 2013年

17

实际方法:

尽快将袜子从未分类的绒头中一次取出,并成堆放置在您面前。绒头应以节省空间的方式排列,所有的袜子都指向相同的方向。桩数受您可以轻松到达的距离的限制。应该(尽可能快地)选择袜子放在上面的一堆上,方法是将袜子放在看起来像袜子的那堆上;可以容忍偶然的I型(将袜子放在不属于它的堆上)或II型(在已有一堆类似袜子的情况下将袜子放在自己的堆中)错误-最重要的考虑因素是速度

一旦所有的袜子都堆成一堆,就迅速穿过多袜子堆,成对地将它们移开(这些都将移向抽屉)。如果堆中有不匹配的袜子,则将它们重新堆放到最佳状态(在尽可能快的约束内)。处理完所有的多袜袜子后,将剩余的可配对袜子配对,这些袜子由于II型错误而没有配对。糟糕,您完成了-我有很多袜子,在大部份脏掉之前不要洗它们。另一个实用注意事项:我利用它们的弹性特性,将一对袜子中的一个的顶部向下翻转,使它们在运输到抽屉中和在抽屉中时保持在一起。


15

从您的问题很明显,您在洗衣方面没有太多实际经验:)。您需要一种能够与少量不可配对的袜子配合使用的算法。

到目前为止,答案还没有充分利用我们的人类模式识别功能。Set游戏提供了如何做到这一点的线索:将所有袜子放在二维空间中,这样您既可以很好地识别它们,又可以轻松地用手抓住它们。这会将您限制在大约120 * 80厘米左右的区域。从那里选择您识别的对,然后将其删除。将多余的袜子放在自由空间中,然后重复。如果您为容易辨认袜子的人洗衣服(小孩子会想到),则可以通过先选择那些袜子来进行基数排序。仅当单袜子的数量少时,此算法才有效


我通常就是这样做的。比每次遍历所有剩余的袜子要好得多。
yu_ominae 2013年

好的方法,我认为它也可以应用于一些实际的CS问题。您能否添加这样的示例(CS问题,我们可以使用类似的方法来解决问题)?此外,该解决方案如何扩展成千上万只袜子?
阿米特

我认为这与1月20 日之后的另一个答案stackoverflow.com/a/14423956基本相同。均为+1。人类视觉系统在很大程度上是平行的。
尼斯,

15

拿起第一只袜子,放在桌子上。现在选择另一只袜子;如果匹配第一个选择,则将其放在第一个之上。如果不是这样,请将其放在桌子上,与第一个相距很小的距离。选择第三只袜子;如果它与前两个匹配,则将其放在上面或与第三个相距很小的距离。重复直到您捡起所有袜子。


1
这是唯一有效的答案。所有其他人都忽略了这样的事实,即花费最多的时间来区分相似的袜子(因此,通过物理外观将它们混在一起会使情况更糟)。
2014年

为了好玩,我编写了将袜子堆积到小的python程序gist.github.com/justinfay/53b574cf0a492f6795ef
Justin Fay

12

为了说明从一堆袜子配对的效率如何,我们必须首先定义机器,因为配对不是通过图灵机还是通过随机存取机完成的,通常这是机器的基础。算法分析。

机器

该机器是对现实世界中称为人类的元素的抽象。它可以通过双眼从环境中读取信息。而且我们的机器模型能够使用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)),其中rw对于环境的读取和环境写入操作的因素分别为袜子的合理费用。省略了逻辑和算术运算的成本,因为我们假设需要花费恒定数量的逻辑和算术运算来确定2个袜子是否属于同一对。这可能并非在每种情况下都是可行的。



@WillNess Yep,还有更多解释
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. 找到它的匹配项。
  3. 如果没有匹配项,请将其放在“丢失”堆上。
  4. 从1.开始重复,直到不再有最独特的袜子。
  5. 如果少于6根袜子,请转到11。
  6. 盲目地将所有袜子与邻居配对(不要打包)
  7. 查找所有匹配的对,将其打包,然后将打包的对移动到“匹配的”堆中;如果没有新的匹配项,则将“索引”加1
  8. 如果“索引”大于2(可能是数值,取决于袜子的数量,因为袜子数量越多,盲目配对的机会就越少)转到11
  9. 洗净其余的
  10. 转到1
  11. 忘记“索引”
  12. 选择一只袜子
  13. 找到它的一对
  14. 如果没有袜子对,将其移至“缺失”桩
  15. 如果找到匹配,将其打包,然后将其移动到“匹配”的桩上
  16. 如果还有更多,那么一只袜子会跳到12
  17. 如果只剩一个,请转到14
  18. 微笑满意:)

此外,还可以添加检查是否有损坏的袜子,就像将袜子卸下一样。它可以插入2到3之间以及13到14之间。

我期待听到任何经验或更正。


写完这些之后,我会每次使用它。它帮助我变得更有效率,现在工作也不再那么枯燥。
Sasa

11

在对袜子进行排序时,我会进行近似的基数排序,将袜子放在其他具有相同颜色/图案类型的袜子附近。除了当我能在即将放下袜子的位置/附近看到完全匹配的情况时,我会在那一点提取这对袜子。

几乎所有其他算法(包括usr得分最高的答案)进行排序,然后删除对。我发现,作为一个人,最好一次减少所考虑的袜子数量。

我这样做是:

  1. 挑选一个有特色的袜子(无论什么东西,我首先注意到)。
  2. 根据与该位置的相似性,从该位置拉袜子,从该概念位置开始进行基数排序。
  3. 将新袜子放到当前桩堆附近,并根据距离的不同而不同。如果发现袜子相同,则将其放在另一只袜子的上面,在那儿成对,然后将它们取出。这意味着将来的比较会花费更少的精力来查找正确的位置。

这利用了人类在O(1)时间中进行模糊匹配的能力,这在某种程度上等效于在计算设备上建立哈希映射。

首先拉动独特的袜子,您就可以腾出空间来“放大”那些不太独特的特征。

在消除了荧光色,带条纹的袜子和三双长袜子之后,您可能最终会得到大部分是白色的袜子,这些袜子根据它们的磨损程度大致排序。

在某些时候,袜子之间的差异很小,以至于其他人不会注意到它们之间的差异,因此不需要任何进一步的匹配工作。


10

每当您拿起袜子时,都将它放在一个地方。然后,您拿起的下一只袜子,如果与第一只袜子不匹配,请将其放在第一只袜子旁边。如果是这样,那会有一对。这样一来,实际上有多少种组合并不重要,每只袜子您只有两种可能-袜子中已经有匹配的东西,或者没有,这意味着您将其添加到数组中的某个位置。

这也意味着您几乎肯定不会将所有袜子都放在阵列中,因为匹配的袜子会被移除。


O(n)
Pykler

2
@Pykler-最好的情况下为O(n),最坏的情况下为O(n * n)。
Vilx-

2
那就是假设您无法在所有已经看过的袜子的脑海中创建一个完全唯一的哈希,对于我来说,这是一个O(1)来匹配我以前见过的袜子,并放在等待匹配的哈希中
Pykler

10

考虑大小为“ N”的哈希表。

如果我们假设服从正态分布,则将至少一个袜子映射到一个存储桶的“插入”的估计数目为NlogN(即,所有存储桶已满)

我把这个作为另一个难题的一部分,但是我很高兴被证明是错误的。 这是我在同一篇博客上的文章

令“ N”对应于您拥有的袜子的独特颜色/图案数量的近似上限。

一旦发生碰撞(又称匹配),只需脱去那双袜子。下一批NlogN袜子重复相同的实验。这样做的好处是,由于人脑的工作方式,您可能会进行NlogN并行比较(冲突分辨率)。:-)


10

袜子,无论是真袜子还是类似的数据结构,都将成对提供。

最简单的答案是在允许将袜子分开之前,应该已初始化该袜子的单个数据结构,其中包含指向左右袜子的指针,因此可以直接或通过袜子对来引用袜子。袜子也可以扩展为包含指向其伙伴的指针。

这样可以通过抽象层将其删除来解决任何计算配对问题。

将相同的想法应用于袜子配对的实际问题,显而易见的答案是:永远不要让袜子成双。袜子是成对提供的,成对放入抽屉(可能是通过将它们压在一起),成对穿着。但是,可能无法配对的是洗衣机,因此,所需要的只是一种物理机制,可以使袜子保持在一起并有效地进行清洗。

有两种物理可能性:

对于保持指向每只袜子的指针的“对”对象,我们可以有一个布袋,用来将袜子固定在一起。这似乎是巨大的开销。

但是,为了让每只袜子都能互相参考,有一个整洁的解决方案:弹出式吸嘴(如果您是美国人,则为“快照按钮”),例如:

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

然后,您要做的就是在脱下袜子并将它们放入洗涤篮后立即将它们扣在一起,再一次消除了需要将袜子与“双”概念的物理抽象配对的问题。


它不能回答问题,因为处理已配对的数据很容易,问题是当数据为未配对并且要配对时该怎么做。
阿米特(Amit)2015年

8

如果“移动”操作非常昂贵,而“比较”操作很便宜,并且您仍然需要将整个集合移动到一个缓冲区中,该缓冲区的搜索速度比原始存储要快得多...只需将排序集成到必需项中移动。

我发现将分类过程集成到悬挂晾干过程中变得轻而易举。无论如何,我都需要捡起每只袜子,然后将其挂起来(移动),将它挂在琴弦上的特定位置上几乎不需要花什么钱。现在只是不强制搜索整个缓冲区(字符串),我选择按颜色/阴影放置袜子。现在,我挂上每只袜子之前,我先看一下它的“右侧附近”,如果已经有匹配的袜子-这会将“扫描”限制为其他2-3只袜子-如果是,我将另一个挂在它旁边。然后我将它们成对成卷,同时从琴弦上移开,晾干。

现在,这似乎与最佳答案中建议的“按颜色形成桩”没有什么不同,但首先,通过不选择离散桩,而是选择范围,我对将“紫色”变为“红色”还是“蓝色”桩没有问题。它只是之间。然后,通过集成两个操作(悬挂晾干和分拣),悬挂时分拣的开销约为单独分拣的10%。


这种方法还有另外两个优点:与滚筒式烘干机相比,线烘干损失的袜子IME少得多,并且分类过程可以扩展到其余的衣物,因此(例如)所有毛巾彼此靠近可以折叠起来。线,装箱并直接带到他们的仓库。它还可以通过两次省力工作,将衣服收起再放下。
cphlewis 2015年

8

我刚刚完成了袜子的配对,发现最好的方法如下:

  • 选择其中一只袜子放好(为那双袜子创建一个“桶”)
  • 如果下一个是前一个的配对,则将其放入现有存储桶,否则创建一个新存储桶。

在最坏的情况下,这意味着您将拥有n / 2个不同的存储桶,并且您将有n-2个决定,以确定哪个存储桶包含当前袜子对。显然,如果只有几对,则此算法效果很好;我做了12对。

它不是很科学,但是效果很好:)


这仍然是O(n ^ 2)算法,因为每当您拔出新袜子时都必须遍历每个存储桶。但是,考虑到即使在同一批次中购买的袜子也存在细微差异,从而使它们有效地成对唯一(甚至是唯一唯一)的事实,反正没有更好的方法
Semisonic

同意,但是我的算法假设人类正在进行配对。因此,当您搜索匹配的存储桶时,您的脑海中就会浮现一种缓存,因此您实际上并不需要遍历存储桶。不确定在配对过程中我是否为这种缓存机制构建了哪种数据结构。
maestro

8

我的解决方案不完全符合您的要求,因为它正式需要O(n)“额外”空间。但是,考虑到我的条件,这在我的实际应用中非常有效。因此,我认为这应该很有趣。

与其他任务结合

我的特殊情况是我不使用烘干机,只是将衣服挂在普通的干衣机上。挂布需要进行O(n)操作(顺便说一句,在这里我总是考虑垃圾箱包装问题),而从本质上讲,该问题需要线性“多余”空间。当我从水桶中取出新袜子时,如果袜子已经挂了,我会尝试将其挂在袜子对旁边。如果是一对新袜子,我旁边会留一些空间。

Oracle机器更好;-)

显然,这需要一些额外的工作来检查是否有匹配的袜子已经挂在某处,并且它将为计算机呈现O(n^2)系数约为的解1/2。但是在这种情况下,“人为因素”实际上是一个优势-我通常可以很快(几乎O(1))识别出匹配的袜子(如果已经挂了)(可能涉及了一些不可察觉的脑内缓存)-认为这是一种像Oracle机器中那样有限的“ oracle” ;-)在某些情况下,人类比数字机器具有这些优势;-)

快拥有了O(n)

因此,将袜子配对问题和悬挂布问题联系起来,我可以O(n)免费获得“额外空间”,并且有一个O(n)及时的解决方案,比简单的悬挂布需要更多的工作,并且可以立即使用完整的袜子对。即使在一个非常糟糕的星期一早晨也穿上袜子... ;-)


8

我希望我可以为这个问题做出新的贡献。我注意到所有答案都忽略了一个事实,您可以在两个方面执行预处理,而不会降低整体洗衣性能。

另外,即使对于大家庭,我们也无需假设大量的袜子。将袜子从抽屉中取出并穿上,然后将它们扔在要清洗的地方(可能是垃圾箱)。虽然我不会称“ bin”为“ LIFO堆栈”,但我可以肯定地说

  1. 人们把两只袜子都扔在垃圾桶的同一区域,
  2. 垃圾箱在任何时候都不是随机的,因此
  3. 从该垃圾箱的顶部取出的任何子集通常都包含一对袜子。

由于我所知道的所有洗衣机的大小都是有限的(不管您要洗多少袜子),并且实际的随机化发生在洗衣机中,所以无论我们拥有多少袜子,我们总会有很小的子集,其中几乎没有单身人士。

我们的两个预处理阶段是“必须将袜子放在晾衣绳上”和“从晾衣绳上取出袜子”,以使袜子既清洁又干燥。与洗衣机一样,晾衣绳是有限的,我认为我们在整个生产线中都可以看到袜子。

这是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%的袜子已经配对,剩下的袜子子集很小,而且这个子集已经(有点)聚集了(在预处理步骤之后,我不会在篮子中引入太多的熵)。另一件事是,其余集群通常足够小,可以立即处理,因此可以将整个集群从购物篮中取出。

这是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堆栈的垃圾桶,一台有限的普通洗衣机和一排有限的普通晾衣绳-但这仍然适用于大量的袜子。

关于并行性:只要将两只袜子扔到同一个料箱中,就可以轻松地并行化所有这些步骤。


袜子只是将某个数据库中的任意对象配对的隐喻。
艾米特

1
知道了,没发现您是作者。如果您想要一个通用的解决方案,那么您确实应该这么说。无论如何,考虑到您所拥有的任何信息都没有错,除非您必须提出一个通用的解决方案-放弃该解决方案的可重用性可能会带来更好的性能。在这种情况下,从整体上考虑用例和可用数据库是有益的。但是,对您的特殊问题的特殊回答涉及外观相似的袜子,例如大小不同的黑色袜子,因此在某些情况下不适用。
菲利普·弗伦克

1
同样,您没有获得超过2k的投票,因为您询问了有关配对数据库中任意对象的问题。由于袜子的本质(与数据相对,您无法复制),您特别限制了该问题,甚至鼓励您使用这样的事实,即可以轻松将袜子与配偶的袜子区分开。如果您问有关袜子的问题,请不要期望答案是关于数据库的;-)
Philipp Flenker

1
这里有一些假设:一个普通的洗衣机,一条普通的晾衣绳,以及您同时将两只袜子扔进垃圾箱的事实,这意味着在大多数情况下,两只袜子都在同一台机器上,并且数量因此,剩余的袜子要分类。但是,既然您真的想要一个有关在数据库中存储任意对象的答案,那么进一步讨论我的解决方案真的有用吗?
菲利普·弗伦克

1
正如我说的,我认为我已经解决了您要求的所有内容,除了元素差异性问题之外,其他人已经回答了这一问题。我不是想在这里做些冲洗,但是前一段时间我在这个答案上做了很多努力,对于您现在经历了一些答案并声称他们没有回答原始问题,我感到非常失望。 。您为什么不只留下整个线程-在您问了2年多之后,仍然是一个有趣的读物?
Philipp Flenker

8

我已经采取了简单的步骤来减少我的工作量,从而节省了O(1)的时间。

通过将输入减少为两种袜子(用于休闲的白色袜子,用于工作的黑色袜子)中的一种,我只需要确定我手中有两只袜子。(从技术上讲,由于它们从未一起洗过,因此我将过程减少为O(0)时间。)

需要一些前期工作才能找到理想的袜子,并购买足够数量的袜子,以消除对您现有袜子的需求。因为在我需要黑袜子之前就已经这样做了,所以我的努力​​很小,但是里程可能会有所不同。

在非常流行和有效的代码中已经多次看到了这种前期工作。例子包括将pi#DEFINE'ing到十进制小数(存在其他例子,但这就是现在想到的那个例子)。


7

使用模式作为哈希表,创建一个哈希表将用于不匹配的袜子。一次又一次地遍历袜子。如果该袜子在哈希表中具有模式匹配项,则将其从表中取出并配对。如果袜子不匹配,则将其放入桌子。


如问题中特别提到的,如何不就地执行它?
2015年

7

您的n双袜子进行排序的问题是O(n)。在将它们扔进洗衣篮之前,先将左侧的一个穿到右侧的一个上。取出它们时,您要剪断线并将每对放入抽屉中-n对上有2次操作,所以O(n)。

现在,下一个问题就是您是否自己洗衣服,而您的妻子是否洗衣服。在完全不同的问题领域中,这可能是一个问题。:)


这并不能回答袜子只是个比喻的问题。
2015年

问题是如何从未配对的袜子中配对袜子,而不是如何避免需要配对。
2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.