假设有10个数组,我们必须找出给定数组中的所有常见元素。
目前我正在选择第一个数组,并且对于第一个数组中的每个元素,我遍历所有剩余的数组,但这会增加时间复杂度。
有没有任何好的算法可以做到最少没有比较?
答案 0 :(得分:5)
我假设你想要数组的intersection。
基于哈希的方法:
这假定每个单独数组中有唯一的元素。
将第一个数组中的所有元素插入到要计数的元素的哈希映射中,计数从1开始。
然后遍历剩余的数组,增加每个遇到元素的计数。
最后,输出计数等于数组数的所有元素。
您可以在C#中使用Dictionary
或在C ++ 11中使用unordered_map
。您也可以在此处使用有序地图(例如,C ++中的map
)。
基于排序的方法:
单独对所有数组进行排序。
同时遍历所有数组,保持每个数组中包含一个元素的heap或binary search tree。在每个步骤中,从结构中删除最小值,并从该元素所在的数组中添加下一个元素。
每当最小值=最大值时,输出该值。
我的猜测是,这可能与set_intersection
非常相似。
处理每个单独数组中的非唯一值:
(即1 2 2 3 4
和2 2 4 5
的“交叉点”应输出2 2 4
)
您需要记住上次输出值的时间,并且只在插入了大于或等于数组数的元素后才输出值。
如果你不这样做,你会得到太多结果。查看交叉1, 1
和1, 1
以及1, 1
的简单示例。预期输出为1, 1
,但这会发生:
结构:1, 1, 1
最小值=最大值= 1,输出1
删除第1个阵列中的1并插入第2个1
结构:1, 1, 1
最小值=最大值= 1,输出1
删除第二个数组中的1并插入第二个1
结构:1, 1, 1
最小值=最大值= 1,输出1
删除第3个阵列中的1并插入第2个1
结构:1, 1, 1
Min = max = 1,输出1
现在输出为1, 1, 1, 1
。
插入时,请确保始终在所有其他相等值之后插入(即将其视为大于它们)。为此,您只需将自动递增的唯一ID作为辅助比较值。
如果你不这样做,你可以继续从同一个数组中删除元素,这会很快将你带到另一个元素,因此你不一定会输出正确数量的非唯一值。
例如,如果我们将1, 1, 1, 2
和1, 1, 1
相交,您可能会碰巧从第一个数组中重复删除,分3步进入2
,但是,由于在上面,我们只输出每两步,因此我们只有2而不是3 1
。
答案 1 :(得分:4)
在c ++中有一个标准算法std::set_intersection。它适用于两个已排序的序列。我想你几乎不会比这更好。对所有数组进行排序,然后按顺序调用set_intersection
以获得结果。总体复杂度为O(N*log(N))
,其中N是数组的长度(如果长度不同,则为最大长度)。
答案 2 :(得分:0)
如果您是关于C#的,那么有一个名为language-integrated query的好东西,它可以尽可能简化查询集合并提供并行执行(PLINQ)。在C#中,您只需write inner join query即可获得多个数组。