昨天,我在洗衣服时把袜子配对,结果发现我这样做效率不高。我在做一个天真的搜索——挑选一只袜子,然后“反复”寻找那一双袜子。这需要平均在n/2*n/4=n2/8袜子上迭代。
作为一名计算机科学家,我在想我能做什么?排序(根据大小/颜色/…)当然是为了实现O(NlogN)解决方案。
哈希或其他不到位的解决方案是不可选择的,因为我无法复制我的袜子(如果可以的话,这可能很好)。
因此,问题基本上是:
给定一堆n双袜子,其中包含2n个元素(假设每只袜子正好有一对匹配的袜子),用对数的额外空间高效地将它们配对的最佳方式是什么?(如果需要的话,我相信我可以记住这些信息。)
我将感谢回答以下方面的问题:
大量袜子的一般理论解。袜子的实际数量没有那么多,我不相信我的配偶和我有超过30双。(而且很容易区分我的袜子和她的袜子;这也可以用吗?)它是否等同于元素清晰度问题?
这个问题实际上很有哲理。本质上,这是关于人们解决问题的能力(我们大脑的“湿件”)是否等同于算法所能完成的任务。
袜子分类的一个明显算法是:
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
现在这个问题的计算机科学都是关于步骤的
“如果s与N中的袜子t配对”。我们能多快“记住”到目前为止所看到的东西?“从N中删除t”和“将s添加到N”。跟踪我们目前所看到的情况有多贵?
人类将使用各种策略来实现这些目标。人类的记忆是关联的,类似于哈希表,其中存储值的特征集与相应的值本身配对。例如,“红色汽车”的概念映射到一个人能够记住的所有红色汽车。有完美记忆的人有完美的映射。大多数人(以及其他大多数人)在这方面都不完美。关联映射的容量有限。映射可能会在各种情况下(一杯啤酒太多)消失,被错误记录(“我认为她的名字是贝蒂,而不是内蒂”),或者即使我们观察到真相已经改变,也永远不会被覆盖(“爸爸的车”让人想起“橙色火鸟”,而我们实际上知道他用它换了红色的科迈罗)。
就袜子而言,完美回忆意味着看一只袜子总会产生它的同胞t的记忆,包括足够的信息(它在熨衣板上的位置),以便在恒定的时间内找到t。一个有照片记忆的人会在恒定的时间内完成1和2的任务。
记忆力不太好的人可能会根据自己能力范围内的特征使用一些常识等价类:尺寸(爸爸、妈妈、宝宝)、颜色(绿色、红色等)、图案(菱形、素色等)、风格(脚、膝盖高等)。这通常允许通过内存在恒定时间内定位类别,但随后需要通过类别“桶”进行线性搜索。
一个完全没有记忆或想象力的人(抱歉)只会把袜子放在一堆里,然后对整堆袜子进行线性搜索。
一个整洁的怪人可能会像某人建议的那样使用数字标签。这打开了完全排序的大门,允许人类使用与CPU完全相同的算法:二进制搜索、树、散列等。
因此,“最佳”算法取决于运行该算法的湿软件/硬件/软件的质量,以及我们是否愿意通过对其施加总订单来“欺骗”。当然,一个“最好”的元算法是雇佣世界上最好的袜子分类器:一个人或机器可以通过不断的时间查找、插入和删除,在1-1关联存储器中获取并快速存储大量的袜子属性集N。这样的人和机器都可以采购。如果你有一双袜子,你可以在O(N)时间内将所有袜子配对N双,这是最佳的。总订单标签允许您使用标准哈希来获得与人工或硬件计算机相同的结果。
成本:移动袜子->高,查找/搜索袜子排成一排->小
我们想做的是减少移动次数,并用搜索次数进行补偿。此外,我们还可以利用智人的多威胁环境,在解密缓存中保存更多的东西。
X=您的,Y=您的配偶
从所有袜子的A堆开始:
选择两个袜子,将相应的X袜子放在X线上,将Y袜子放在Y线上的下一个可用位置。
直到A为空。
对于每行X和Y
选择行中的第一只袜子,沿着行搜索,直到找到相应的袜子。放入相应的袜子成品线。可选当您搜索线条时,当前正在查看的袜子与之前的袜子相同,请对这些袜子执行步骤2。
可选地,在第一步中,您从该行中拾取两个袜子,而不是两个,因为缓存内存足够大,我们可以快速识别其中一个袜子是否与您正在观察的行上的当前袜子匹配。如果你有幸拥有三只手臂,那么考虑到受试者的记忆足够大,你可以同时解析三只袜子。
直到X和Y都为空。
Done
然而,由于这与选择排序具有相似的复杂性,由于I/O(移动袜子)和搜索(搜索袜子的行)的速度,所花费的时间要少得多。
这是基于比较的模型中的Omega(n log n)下限。(唯一有效的操作是比较两只袜子。)
假设你知道你的2n只袜子是这样排列的:
p1 p2 p3。。。pn pf(1)pf(2)。。。功率因数(n)
其中f是集合{1,2,…,n}的未知排列。知道这一点不会使问题变得更难。有n个!可能的输出(上半部分和下半部分之间的匹配),这意味着您需要log(n!)=Omega(n log n)比较。这可通过分类获得。
由于您对元素区别性问题的连接感兴趣:证明元素区别性的Omega(n log n)界限比较困难,因为输出是二进制的yes/no。这里,输出必须是匹配的,并且可能输出的数量足以获得一个合适的界限。然而,有一个变量与元素的区别有关。假设你有2n只袜子,想知道它们是否可以唯一配对。您可以通过将(a1,a2,…,an)发送到(a1,a1,a2、a2,…、an,an)来获得ED的缩减。(附带地,通过拓扑结构,ED的硬度证明非常有趣。)
我认为,如果只允许等式测试,那么原始问题应该有一个Omega(n2)边界。我的直觉是:考虑一个测试后添加边的图形,并认为如果图形不密集,则输出不是唯一确定的。
对于p双袜子(n=2p只袜子),我实际上是这样做的:
从袜子堆里随便拿一只袜子。对于第一只袜子,或者如果之前选择的所有袜子都已配对,只需将袜子放入前面未配对袜子“阵列”的第一个“槽”中。如果有一个或多个选定的未配对袜子,请对照阵列中的所有未配对袜子检查当前袜子。在构建阵列时,可以将袜子分为普通类别或类型(白色/黑色、脚踝/圆领、运动型/连衣裙),并“向下搜索”以仅比较同类。如果你找到了一个可以接受的匹配,把两只袜子放在一起,然后把它们从阵列中去掉。如果没有,请将当前袜子放入阵列中第一个打开的插槽中。对每只袜子重复上述步骤。
这种方案的最坏情况是,每双袜子都不同,必须完全匹配,而且你挑选的第一双n/2袜子都不同。这是你的O(n2)场景,极不可能。如果袜子的独特类型的数量t小于袜子对的数量p=n/2,并且每种类型的袜子都足够相似(通常在穿着相关的术语中),使得该类型的任何袜子都可以与任何其他袜子配对,那么正如我上面所推断的,你必须与之进行比较的袜子的最大数量是t,之后你拉动的下一只袜子将与未配对的袜子之一相匹配。这种情况在普通袜子抽屉中比在最坏情况下更可能发生,并将最坏情况的复杂性降低到O(n*t),其中通常t<<n。