我正在寻找一种有效的方法来比较数字列表,看看它们是否匹配任何轮换(比较2个循环列表)。
当列表没有重复项时,选择最小/最大值并在比较之前旋转两个列表。 但是当可能存在许多重复的大值时,这并不是那么简单。
例如,列表[9, 2, 0, 0, 9]
和[0, 0, 9, 9, 2]
是匹配,其中[9, 0, 2, 0, 9]
不匹配(因为订单不同)。
这是一个有效的无效功能的例子。
def min_list_rotation(ls):
return min((ls[i:] + ls[:i] for i in range(len(ls))))
# example use
ls_a = [9, 2, 0, 0, 9]
ls_b = [0, 0, 9, 9, 2]
print(min_list_rotation(ls_a) == min_list_rotation(ls_b))
这可以提高效率......
然而,它仍然不是一种非常有效的方法,因为它依赖于检查许多可能性。
是否有更有效的方法来执行此比较?
答案 0 :(得分:0)
如果要查找大量列表中的重复项,可以将每个列表旋转到其按字典顺序排列的最小字符串表示形式,然后对列表列表进行排序或使用哈希表查找重复项。这个规范化步骤意味着您不需要将每个列表与每个其他列表进行比较。有一些聪明的O(n)算法可以找到https://en.wikipedia.org/wiki/Lexicographically_minimal_string_rotation所描述的最小旋转。
答案 1 :(得分:0)
你几乎拥有它。
您可以独立于其他列表执行某种列表的“规范化”或“规范化”,然后您只需要逐项比较(或者如果你想要的,把它们放在一个地图中,在一个集合中消除重复,......“
1取最小项目,不在其前面(以循环方式)
在您的示例92009中,您应该取第一个0(而不是第二个)
2如果始终相同的项目(例如00000),您只需保留:00000
3如果你有多次使用同一个项目,请选择下一个项目,这是最小的,然后继续,直到找到一个最小路径的唯一路径。
示例:90148301562 =>你有0148 ..和0156 .. =>你拿0148
4如果你不能分开不同的路径(=如果你有无限的平等),你有一个重复的模式:那么,没关系:你带走任何一个。
示例:014376501437650143765:你有相同的模式0143765 ......
就像AAA,其中A = 0143765
5如果您在此表单中列出了列表,则可以轻松比较其中两个。
如何有效地做到这一点:
在列表中迭代以获得最小值Mx(不在其前面)。如果你找到几个,保留所有这些。
然后,从每个最小Mx迭代,获取下一个项目,并保持最小值。如果你进行整个循环,你就会有一个重复的模式。
除了重复模式的情况,这必须是最小的方式。
希望它有所帮助。
答案 2 :(得分:0)
我会在预期的O(N)时间内使用多项式散列函数来计算列表A的散列,以及列表B的每个循环移位。如果列表B的移位具有与列表A相同的散列,则比较实际元素,看它们是否相等。
这个快速的原因是使用多项式散列函数(非常常见!),您可以在恒定时间内计算每个循环移位的散列,因此您可以计算所有循环移位的散列值在O(N)时间。
它的工作原理如下:
假设B有N个元素,那么使用素数P的B的散列是:
Hb=0;
for (i=0; i<N ; i++)
{
Hb = Hb*P + B[i];
}
这是评估P中多项式的优化方法,相当于:
Hb=0;
for (i=0; i<N ; i++)
{
Hb += B[i] * P^(N-1-i); //^ is exponentiation, not XOR
}
注意每个B [i]如何乘以P ^(N-1-i)。如果我们将B向左移动1,则每个B [i]将乘以额外的P,除了第一个。由于乘法在加法上分布,我们可以通过乘以整个散列来立即乘以所有分量,然后修正第一个元素的因子。
B左移的哈希只是
Hb1 = Hb*P + B[0]*(1-(P^N))
第二个左移:
Hb2 = Hb1*P + B[1]*(1-(P^N))
依旧......