Algorithm 寻找共素子阵的有效方法

Algorithm 寻找共素子阵的有效方法,algorithm,time-complexity,Algorithm,Time Complexity,给定一个数组,是否有可能在优于O(N²)的时间内找到该数组的共素数子数组数?共素数数组被定义为数组的连续子集,因此所有元素的GCD都是1。考虑在数组的末尾添加一个元素。现在找到最右边的位置(如果有的话),这样从该位置到刚才添加的元素的子数组就是共素数。因为它是最右边的,所以以添加元素结尾的更短数组都不是共素数。因为它是协素数,所以每个从左边开始并以新元素结尾的数组都是协素数。因此,您已经计算出以新元素结尾的共素数子数组的数量。如果您可以高效地找到最右边的位置(比如在O(logn)而不是O(n)中

给定一个数组,是否有可能在优于O(N²)的时间内找到该数组的共素数子数组数?共素数数组被定义为数组的连续子集,因此所有元素的GCD都是1。

考虑在数组的末尾添加一个元素。现在找到最右边的位置(如果有的话),这样从该位置到刚才添加的元素的子数组就是共素数。因为它是最右边的,所以以添加元素结尾的更短数组都不是共素数。因为它是协素数,所以每个从左边开始并以新元素结尾的数组都是协素数。因此,您已经计算出以新元素结尾的共素数子数组的数量。如果您可以高效地找到最右边的位置(比如在O(logn)而不是O(n)中),那么您可以通过一次将数组扩展一个元素来计算O(nlogn)中的共素数子数组的数量

为了能够找到最右边的位置,可以将整个数组看作是一个完整的二叉树的叶子,将其填充为a长度的二次方。在每个节点上,将所有元素的GCD放在该节点下-您可以在时间O(n)中从下到上执行此操作。数组中的每个连续间隔都可以由大小为O(logn)的节点集合覆盖,这样间隔由节点下的叶子组成,因此可以计算间隔的GCD为时间O(logn)

要找到与当前元素形成共质数子阵列的最右侧位置,请从当前元素开始,检查它是否为1。如果是,你就完了。如果没有,请查看元素的左侧,使用该元素获取GCD,并将结果推送到堆栈上。如果结果为1,则完成,如果不是,则执行相同的操作,但查看是否存在包含2个元素的子树,您可以使用它一次添加2个元素。在接下来的每个步骤中,您都会将要查找的子树的大小增加一倍。你不会总是找到一个你想要的大小的方便的子树,但是因为每个间隔都可以被O(logn)子树覆盖,你应该足够幸运地在时间O(logn)中完成这一步

现在您已经发现当前元素的整个数组不是共素数,或者您已经找到了一个共素数的部分,但是可能会比它需要的更远。堆栈顶部的值是通过获取堆栈上位于其正下方的值的GCD和子树顶部的GCD来计算的。将其从堆栈中弹出,并获取其正下方的值和子树右半部分的GCD。如果你仍然是协素数,那么你不需要子树的左半部分。如果不是,那么你需要它,但也许不是全部。在任何一种情况下,您都可以继续向下查找时间O(log n)中最右边的匹配项

所以我认为你可以找到最右边的位置,在时间O(logn)中与当前元素形成一个共素子数组(无可否认,通过一些非常精细的编程),这样你就可以计算时间O(logn)中的互质子数组的数量

两个例子:

清单1、3、5、7。下一级是1,1,根是1。如果当前元素是13,那么我检查7,发现gcd(7,13)=1。因此,我立即知道GCD(5,7,13)=GCD(3,5,7,13)=GCD(1,3,4,7,13)=1


清单2、4、8、16。下一级是2,8,根是2。如果当前的数字是32,那么我检查16,发现gcd(16,32)=16!=然后我检查8,发现GCD(8,32)=8,然后我检查2,发现GCD(2,32)=2,因此在GCD=1的扩展数组中没有间隔。

我假设在这种情况下,查找两个数字的GCD被视为常数时间。@biziclop…是的,请给出一个示例,说明在给定一个完全互质的列表的情况下,树如何帮助避免将添加的元素与之前的所有元素进行比较?我不明白这怎么可能。我已经添加了一些例子。我认为有可能我们对互质列表的定义不一致。我认为这意味着将列表中所有元素分开的最大数字是1。谢谢!但是对不起,我还是不明白。如果你知道[a,b]是互质的,你怎么知道[a,b,c]是互质的,而没有找到(c,b)的GCD和(c,a)的GCD?如果你说一个互质数组是一个最大数除以数组中所有元素的数是1的数组,那么向数组中添加任何数字都可以保持这个性质。根据这个定义{6,10,15}是互质数组,因为gcd(gcd(6,10,15)=gcd(2,15)=1。因此,{6,10,15,900}也是如此,因为虽然15除以900,但没有比1大的数能除以6,10,15和900。哦,你说得对,我误解了这个定义。谢谢