如何高效地从一堆袜子中匹配成对?

4183

昨天我在整理干净的衣服中的袜子,发现我所做的方法不太高效。 我正在进行一个朴素搜索——选取一只袜子并“迭代”堆以找到它的配对。这需要平均遍历n/2 * n/4 = n2/8只袜子。

作为一名计算机科学家,我在思考我该怎么做?排序(按照大小/颜色/...)当然是想到了实现O(NlogN)解决方案的方法。

哈希或其他非就地解决方案不是选择,因为我无法复制我的袜子(虽然如果我能这样做那会很好)。

所以,问题基本上是:

给定一个包含n对袜子的堆,其中包含2n个元素(假设每只袜子恰好有一个匹配对),使用多达对数额外空间有效地将它们配对的最佳方法是什么? (如果需要,我相信我可以记住那些信息的数量。)

我将感激回答以下方面的答案:

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

484
我使用鸽巢原理从洗衣堆里准确地配对一双袜子。我有三种不同颜色的袜子(红色、蓝色和绿色),每种颜色有两双。每次我会拿起四只袜子,总是组成一双配对的袜子然后开始工作。 - Srinivas
68
鸽巢原理又来了:如果你从 n/2+1 只袜子中选出一个子集,那么必定至少有一对袜子在这个子集中。 - wildplasser
42
好问题!你可能会对我关于相关问题的文章感兴趣,它是关于从一堆袜子中抽出两只匹配袜子的概率讨论:http://blogs.msdn.com/b/ericlippert/archive/2010/03/22/socks-birthdays-and-hash-collisions.aspx - Eric Lippert
387
为什么不孵化一个子进程并使用 waitpid 函数,这样作为父进程,你甚至不需要亲自整理任何袜子? - Mxyk
182
我解决了这个问题,方法是只拥有白色的及膝袜子。它们全部搭配起来都很好看。我可以从一堆袜子里随便拿出任何两只袜子,它们都会搭配好。为了进一步简化问题,我不将袜子配对。我有一个袜子抽屉,我只是把所有的袜子扔进去,没有配对。每天早上我从抽屉里随机拿出两只袜子。我已经将其简化到O(0)。再也不能更简单了 :) - Lee
显示剩余38条评论
38个回答

2592

已经提出了排序方案,但是排序有点过头了:我们不需要顺序;我们只需要相等的组。

因此,哈希就足够了(而且更快)。

  1. 对于每种颜色的袜子,形成一堆。遍历输入篮子中的所有袜子,并将它们分配到颜色堆上。
  2. 遍历每个堆,并通过某些其他指标(例如模式)将其分配到第二组堆中
  3. 递归应用此方案,直到您将所有袜子分配到非常小的堆中,您可以立即进行视觉处理。

SQL Server需要在巨大数据集上进行哈希连接或哈希聚合时,实际上正在执行这种递归哈希分区。它将其构建输入流分发到许多独立的分区中。该方案可线性地扩展到任意数量的数据和多个 CPU。

你不需要递归分区,如果你能找到一个分布密钥(哈希密钥),它提供了足够的桶,每个桶都足够小,可以非常快速地处理。不幸的是,我认为袜子没有这样的属性。
如果每只袜子都有一个名为“PairID”的整数,那么可以根据PairID%10(最后一位)将它们轻松地分配到10个桶中。
我能想到的最好的现实分区方法是创建一个堆叠的矩形:一个维度是颜色,另一个维度是图案。为什么是一个矩形?因为我们需要O(1)随机访问堆。 (3D cuboid也可以,但不太实用。)

更新:

并行计算怎么样?多个人可以更快地匹配袜子吗?

  1. 最简单的并行化策略是让多个工人从输入篮子中取出袜子并将其放入堆中。但这种方法只能扩展到一定程度——想象一下100个人争夺10个堆的情景。同步成本(表现为手碰撞和人类沟通)会破坏效率和加速度(参见通用可伸缩性定律!)。这种方法是否容易出现死锁?不会,因为每个工人只需要同时访问一个堆。只有一个“锁”,就不可能出现死锁。根据人类协调访问堆的方式,可能会出现活锁。他们可能会像网络卡一样使用随机退避,以确定哪张卡可以独占访问网络线路。如果这对NICs有效,那么对人类也应该有效。
  2. 如果每个工人都有自己的一组堆,则几乎可以无限扩展。工人可以从输入篮子中取出大块袜子(它们很少发生争用),在分发袜子时完全不需要同步(因为它们有线程本地堆)。最后,所有工人都需要合并他们的堆集。如果工人形成一个聚合树,我相信可以在O(log (工人数*每个工人的堆数))内完成。

关于元素不同性问题呢?正如文章所述,元素不同性问题可以在O(N)时间内解决。对于袜子问题来说也是一样的(如果只需要一个分配步骤,它也是O(N),我提出多个步骤仅因人类计算能力有限——如果你在md5(color, length, pattern, ...)上进行分配,即所有属性的完美哈希),一个步骤就足够了)。

显然,我们无法比O(N)更快,因此我们已经达到了最优下界

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


80
这正是我所做的!我根据袜子口袋的样式(我只有白色)来堆积它们,这样就可以得到足够的“桶”,以便快速配对每一双袜子。 - Scott Chamberlain
37
我尝试过用这种方法来整理我的袜子(我有30多双),速度非常快。但是我发现一个问题,当我有很多没有图案的白袜子时,无法使用好的哈希算法,这时就变得困难了。在这种情况下,最优的方法是什么? - NothingsImpossible
65
@NothingsImpossible,这就是贫穷的web服务器遭受哈希碰撞攻击的感觉!这些白袜子有什么区别的属性吗?一定有一些你可以依据分发它们的方法。否则,你只能任意地组成配对。 - usr
42
这是基数排序,我认为这是正确的答案。@MarkPeters,我认为你不需要查找表。一次线性遍历可以将袜子转换为数字向量,使得“袜子段”到桶的映射变得微不足道。可以使用字符串将袜子绑定到向量上,这样在最后就不需要再进行另一次线性遍历了。 - Pointy
56
我曾经在大学时认识一个人,他的每双袜子上都缝有“PairIDs”(即配对编号),用线缝在袜子上:1、2、3、4…… - Ryan Lundy
显示剩余31条评论

631

由于人脑的结构与现代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);
}

至少这是我在现实生活中使用的,我发现它非常高效。缺点是需要平坦的表面,但通常很丰富。


253
随着袜子数量的增加,人类的SIMD性能不会比CPU更好。 - Lie Ryan
32
在我看来,这是最好的答案。虽然将日常问题归结为计算机算法很有趣、聪明(并且适用于SO),但对于仅有约60只袜子的集合,使用人类眼睛/大脑的解决能力更加明智。 - drug_user841417
16
如果袜子是均匀分布的,由于生日悖论,你将在任何足够小的袜子集合中注意到一双袜子(除非你可以精确地区分颜色,但我认为不可能)。因此,在这里成为瓶颈的不是人类的颜色匹配算法,而是扩散步骤。 - Thomas
14
不行,因为它们具有不同的袖口花纹、袖口长度、整体长度和黑色阴影(最后一个可能会让我的妻子生气到动手打我)。 - Christian
224
你最好希望自己有偶数只袜子,否则你就要花很长时间来叠袜子了。 - Patrick James McDougle
显示剩余21条评论

285

案例1:所有袜子都是相同的(这就是我在现实生活中做的事情)。

选择任意两只袜子组成一双。常数时间。

案例2:有固定数量的组合(所有权、颜色、大小、纹理等)。

使用基数排序(radix sort)。由于不需要比较,因此仅需线性时间。

案例3:未知组合数(一般情况)。

我们必须进行比较以检查两只袜子是否成对。选择其中一个基于比较的排序算法 O(n log n)

然而,在现实生活中,当袜子数量相对较小(恒定)时,这些理论上最优的算法可能效果不佳。它甚至可能比顺序搜索更花费时间,尽管在理论上需要二次时间。


10
这可能需要比顺序搜索更长的时间,顺序搜索在理论上需要二次时间。是的,这就是为什么我讨厌做这个,也许我应该扔掉所有的袜子,从第一种情况开始。 - Nils
63
拥有全部相同的袜子的缺点在于它们往往会以不同的速度老化。因此,您仍然需要根据它们的磨损程度来尝试匹配它们。(这比仅仅按图案进行匹配更加困难) - SDC
137
拥有60双相同的袜子“因为这样更容易配对”可能会让人误认为你从事与计算机有关的工作。 - Steve Ives
14
如果存在操作(如将一对元素折叠在一起)的话,Case 1 就不是常数时间,而是线性时间,且具有最小的常数因子(其证明留给读者自行练习)。当折叠一对元素和折叠一桶袜子所需的时间不同时,它并不能保持相同的时间。然而,它是按比例扩展的。根据阿姆达尔定律,在忽略开销的情况下,其速度可以无限加速。根据 Gustafson 定律,如果有足够的工人(数量留给读者自行练习),则您可以折叠任意数量的一对元素,而不必担心开销。 - acelent
10
@PauloMadeira 这里的排序是常数时间 - 你只需将袜子一堆一堆地放进抽屉里。在这种情况下,唯一的操作实际上是将袜子穿上脚,这也是常数时间。通过延迟执行穿袜子的步骤(可能会牺牲一些空间,未叠放的袜子占用的空间比叠放的大),可以提高性能。我认为这是值得的,但通常我在与妻子的争论中失败了。 - Travis
显示剩余7条评论

165

非算法性答案,但我这样做时“高效”:

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

  • 步骤2)去沃尔玛,按10个一包的数量购买它们-n包白色和m包黑色。日常生活中不需要其他颜色。

然而,有时我不得不再次这样做(丢失袜子,损坏的袜子等),我也不喜欢经常丢弃完好无损的袜子(我希望他们继续销售同样的袜子参考!),所以我最近采取了不同的方法。

算法性答案:

考虑到如果您只为第二堆袜子拿起一只袜子,那么像您这样进行简单搜索找到相匹配的袜子的几率是相当低的。

  • 因此,随机挑选五个,并记住它们的形状或长度。

为什么是五个?通常人类在工作记忆中记住五到七个不同元素时表现良好——有点像RPN栈的人类等价物——五是一个安全的默认值。

  • 从2n-5的堆栈中选择一个。

  • 现在在你画的五个里找一个匹配(视觉模式匹配——人类在小型堆栈上做得很好),如果你没有找到,那么将其添加到你的五个中。

  • 随机从堆栈中选取袜子,并将其与你的5+1双进行比较。随着你的堆栈增长,它会降低你的性能,但提高你的胜算。速度更快。

可以自由地写下计算抽取多少样本才能获得50%匹配率的公式。如果我没记错的话,这是一个超几何定理。

我每天早上都这样做,很少需要超过三次抽取——但我有n双相似的m形白色袜子(大约10双左右)。现在你可以估计我的股票堆栈的大小了 :-)

顺便说一下,我发现每次需要一双袜子时对所有袜子进行排序的交易成本总和远远小于只做一次并绑起袜子。及时制造更好,因为这样你就不必绑袜子了,并且还有边际收益递减(也就是说,你继续寻找那两三只袜子,当它们在洗衣房里或其他地方时,你需要花费时间来匹配袜子)。


28
支持“非算法”答案。这正是我所做的,而且效果非常好。如果您在早上把洗好的袜子放在后面并从抽屉前面拿出来,就不会有更换问题了。所有袜子都能均匀磨损。当我开始注意到其中一只袜子磨损时,我就把完全替换掉这整类袜子的购物清单列出来。对于旧袜子,我会把最好的20%捐给Goodwill(用塑料袋封口以防混在一起),其余的则扔掉。此时,80%的袜子仅剩下6个月的寿命,因此不需要浪费它们。 - FastAl
2
顺便提一下,(1) 捆绑袜子会导致弹性袜子被拉伸并更快地磨损。减少拥有不同种类的袜子可以避免捆绑。(2) 限制袜子的种类的缺点是对于某些注重时尚的人来说,这种方法可能不适合。 - FastAl
3
我来这里特意发布你的“非算法”回答。就像真正的计算机科学一样,大多数人从不足够关注数据及其结构。 - bkconrad
1
在我的情况下,我不需要步骤(1),因为它们会自动丢弃,但不幸的是不成对。袜子往往以恒定的速率消失,通常约2个月足以追踪10双。 - rupps
3
每天生活中不需要其他颜色,只有一个白色包和m个黑色包。选择袜子的好标准规则是要么与裤子的颜色相匹配,要么与腰带的颜色相匹配。因此,最常用的颜色可能是黑色、蓝色、灰色和一些棕色。很难想象一个人需要很多白袜子。 - Andrea Lazzarotto
显示剩余3条评论

112

我的做法是首先拿起第一只袜子并放下(比如,放在洗衣盆的边缘)。然后我拿起另一只袜子并检查它是否与第一只袜子相同。如果相同,我就把它们都拿走。如果不同,我就把它放在第一只袜子旁边。接着我拿起第三只袜子并将其与前两只(如果它们还在)进行比较,以此类推。

这种方法可以在数组中相对容易地实现,假设“删除”袜子是一种选项。 实际上,您甚至不需要“删除”袜子。如果您不需要对袜子进行排序(参见下文),那么您可以只是移动它们并最终得到一个数组,其中所有袜子都排成一对。

假设袜子唯一的操作是比较相等,那么该算法基本上仍然是一个n2算法,尽管我不知道平均情况(从未学过如何计算)。

当然,排序可以提高效率,特别是在现实生活中,您可以轻松地在两只其他袜子之间“插入”一只袜子。在计算机领域中,可以通过树来实现相同的效果,但需要额外的空间。当然,我们回到了NlogN(如果有几只袜子按排序标准不同但不出自同一对,则会更多)。

除此之外,我想不出其他什么,但这种方法在现实生活中似乎相当有效。 :)


8
这也是我所做的(请注意,如果只是留下空格,则插入操作的时间复杂度仍为 O(1)),但在理论上有大量袜子时它难以扩展。 - Mooing Duck
15
与理论上大量种类的袜子一起使用时,其性能表现不佳。 - Steven Lu
3
在将袜子配对的目标中,将一只袜子插入另外两只袜子之间有什么作用?袜子数量未知。:-x - JoeBrockhaus
这也是我的做法,因为我只有4到5种不同类型的袜子,所以我总是能够快速地找到不匹配的袜子,因此在实际应用中,它就像JonHanna所描述的理想哈希一样,并且具有O(n)的可扩展性。 - Jacob Eggers
排序,当然可以提高效率 -- 不,它当然会产生相反的效果。 - Jim Balter
显示剩余11条评论

62
这是在问错误的问题。正确的问题是,为什么我要花时间整理袜子?当您用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双)将占用1.5立方码的空间(假设一双新袜子占用20立方英寸)。这是一个巨大的空间。假设他们用一个大箱子把袜子送到你手中,那个箱子大约是一个立方体,每边长3英尺4英寸。 - AJMansfield
2
@AJMansfield 有一个有效的关注点。然而,我不同意你的一些数字。我会采用只有40年(25...65岁)的时间跨度(即不住在父母/宿舍等地方和退休之间的时间,见上文)。此外,我认为一双鞋子在原包装中占用的空间更像是0.5x4x6英寸。这些数字会大大降低你的空间估计! - hyde
1
第四步是不必要的浪费,-1。 - Dan Bechard
2
对于那些可能被AJMansfield的测量所困惑的人的指南,转换为公制单位:假设一双新袜子占据327立方厘米的空间,则总共需要占据1.14立方米的空间。这是一个巨大的空间。假设他们用一个大致为正方体的盒子将其交付给您,那个箱子的每边长约为1.04米。 - Joey
一个基于好奇心的问题怎么会是“错误的问题”?这就是经典的StackOverflow... - Timmmm

54

理论上最大的时间复杂度是O(n),因为你需要碰到每只袜子(除非有些已经配对好了)。

你可以用基数排序来实现O(n)的效率。你只需要为桶选择一些属性即可。

  1. 首先你可以选择 (她的袜子, 我的袜子) - 将它们分成两堆,
  2. 然后按颜色分类(颜色的顺序可以任意,例如按字母顺序排列颜色名称)- 把它们按颜色分成堆(记得对于同一堆中的所有袜子保持从第一步开始的初始顺序),
  3. 然后是袜子的长度,
  4. 接下来是纹理, ....

如果你能选择有限数量但足以唯一标识每对袜子的属性,那么你应该在O(k*n)内完成,如果我们考虑k是有限的,则为O(n)。


3
袜子通常以4件装或更多的包装出售,因为这样更便宜,但也会导致它们难以区分。为了解决这个问题,我的妻子会在我买的每双新袜子上缝一个微小的标记。每对袜子的标记颜色都不同,如果颜色用完了,就用不同的形状。采用这种方法,你甚至不需要一组有限的属性。只需在每双袜子上缝上一个独特的编号即可。 :) 对于额外的加分,请使用二进制码。 - Vilx-
32
@Vilx- 为什么?不是整个意义在于它们无法区分吗? - flup
5
@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
显示剩余8条评论

35
作为一个实用的解决方案:
  1. 快速将袜子分类成易于辨别的堆。 (按颜色分堆)
  2. 对每个堆进行快速排序,并使用袜子长度进行比较。 作为人类,您可以很快地决定使用哪只袜子来分割,从而避免最坏情况。 (您可以并行看到多只袜子,利用这一点!)
  3. 当堆达到您舒适的阈值时停止排序,以便立即找到成对袜子和无法成对的袜子。

如果您有1000只袜子,8种颜色和平均分布,则可以在c * n时间内制作每个125只袜子的4堆。 如果阈值为5,则您可以在6次运行中对每个堆进行排序。 (计算将袜子扔到正确堆上需要2秒钟,请耗时不到4小时。)

如果您只有60只袜子,3种颜色和2种类型的袜子(你的/你妻子的),则可以在1次运行中对每个10只袜子的堆进行排序。 (再次阈值= 5)。 (计算将袜子扔到正确堆上需要2秒钟,所需时间为2分钟。)

初始桶排序将加速您的过程,因为它在c * n时间内将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
人类优化:我认为作为人类,在第二步中,你应该将袜子随意放置,大致按照顺序排列,然后再逐渐细化直到排序完成,有点像希尔排序。对于人类来说(视觉估计),这比比较-交换的方法要快得多。 - AndrewC

34

你正在试图解决错误的问题。

解决方案1:每次将脏袜子放入洗衣篮中,都打一个小结。这样洗衣后就不需要额外分类了。可以将其视为在Mongo数据库中注册索引。事先付出一些工作量以节省未来一些CPU开销。

解决方案2:如果是冬天,你不必穿配对的袜子。我们是程序员,只要它起作用,没人需要知道。

解决方案3:分散工作。你希望以异步方式执行这种复杂的CPU处理,而不会阻塞用户界面。把那堆袜子塞进一个袋子里。只有在需要时才寻找一双袜子。这样所需的工作量就少得多。

希望能对你有所帮助!


6
把袜子(或其他衣物)打结会降低洗衣机清洗衣物的能力,并且使得将它们解开以便穿着更加困难。方案 2 会使维护变得越来越困难;在 6 个月后,当您需要一双黑色踝袜与短裤和运动鞋搭配时,六个月里只顾着做任何事情会让找到同样状态(脏/干净,磨损相似)的那双袜子的可能性更小。方案 3 不太“异步”,而更直接地是“懒惰”;只在确实需要的时候做最少量的工作。 - KeithS
1
回复:解决方案2:人们会知道我没有穿配对的袜子,因为他们会在我的Birks鞋里看到它们 :) - Bob Probst
1
@BobProbst 是的,但是你的程序员同伴也会穿着不搭配的袜子和Birks鞋,因此他们会很高兴地注意到他们不是唯一的人。 - Francesco Pasa

28
这个问题实际上涉及哲学层面的思考。本质上,它是在探讨人类解决问题的能力(即我们大脑的“湿件”)是否与算法所能完成的相等。
针对袜子分类的一个显而易见的算法是:
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"。跟踪我们已经看到的内容有多昂贵?
人类会使用各种策略来实现这些。人类的记忆是联想的, 类似于哈希表,其中存储值的特征集与相应的值本身配对。例如,“红色汽车”的概念映射到一个人能够记住的所有红色汽车。拥有完美记忆力的人有完美的映射。在这方面(以及其他大多数方面),大多数人都不完美。联想映射的容量有限。在各种情况下,映射可能会消失(喝了一杯啤酒),记录错误(“我以为她的名字是贝蒂,而不是内蒂”)或者即使我们观察到真相已经改变,也永远不会被覆盖(“爸爸的车”引发了“橙色Firebird”,而我们实际上知道他已经把它换成了红色的Camaro)。
在袜子的情况下,完美记忆意味着查看袜子s总是会产生其配对袜子t的记忆,包括足够的信息(在熨衣板上的位置),以便在常数时间内定位t。具有摄影记忆的人可以始终在常数时间内完成1和2。
记忆不完美的人可能会使用基于其能力跟踪的特征的一些常识等价类:大小(爸爸、妈妈、宝宝)、颜色(绿色、红色等)、图案(菱形格子、纯色等)和样式(脚底袜、高筒袜等)。因此,熨衣板将根据类别划分为几个部分。这通常允许通过记忆在常数时间内找到类别,但然后需要通过类别“桶”进行线性搜索。
完全没有记忆或想象力的人(抱歉)只会将袜子放在一堆中,并对整个堆进行线性搜索。
一个整洁的人可能会像有人建议的那样为每对袜子使用数字标签。这打开了一个总排序的大门,使人类能够使用与CPU相同的算法:二分查找、树、哈希等。

所以,“最佳”的算法取决于运行它的生物硬件/软件的特性和我们愿意通过对成对数据施加完全顺序来“作弊”的意愿。当然,“最佳”-算法是雇用世界上最好的袜子分类器:一个能够获得并快速存储大量袜子属性集N的人或机器,与常数时间查找、插入和删除的1-1关联内存。这样的人或机器都可以采购到。如果你有这样的一个,你可以在O(N)时间内配对所有的袜子,对于N对来说这是最优的。总序标签允许您使用标准哈希来得到相同的结果,无论是使用人还是硬件计算机。


好的,这样就好多了,虽然还是有些错误...但这个问题不是关于那个的。无论 Church-Turing 论题是否正确,人类和我们的计算机都可以分类袜子。(事实上,人类作为高度有限的实体,比图灵机的计算能力要低得多...而我们的计算机也是如此,但限制是不同的。) - Jim Balter
我不同意。当然,我们当前的任何计算机本质上都是一个巨大的DFA(模i/o差异),而不是TM。然而,任何模拟设备,例如我们的身体,都能够模拟无限的纸带。我们还没有一个有用的描述我们的思维计算方式的方法。 - Gene
人类或其他物理设备没有无限的纸带,因为人脑中没有无限的分辨率,也不可能有。学习一些神经科学知识会有所帮助。无论如何,这里并没有深奥的哲学问题,不管你想要注入什么。但是相信你自己的想法吧……这不是这种辩论的场合,我以前已经遇到过太多次了。但我总是被那些几乎解决不了最简单问题(我们所有人都是)的人想象成TM等价而感到很有趣。 - Jim Balter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接