查找来自两组的元素的所有组合,使得它们的几何平均值落入第三组

时间:2017-05-18 17:30:54

标签: arrays algorithm time-complexity geometric-mean

我有一个从1到n的整数。我将每个整数随机分配到三组ABCA ∩ B = B ∩ C = C ∩ A = Ø)中的一组。每个整数都属于一个集合。所以我需要计算(a,b)元素的所有组合,a ∈ A, b ∈ Ba,b的几何平均值属于C。基本上是sqrt(a*b) ∈ C

我的解决方案是首先在大小为n的数组上标记是否每个元素都进入集合A,B或C.然后我遍历数组以查找属于A的所有元素。当我遇到一个时,我再次遍历所有属于B的元素。如果array[sqrt(a*b)] == C,则我添加(a, b, sqrt(a,b))作为一种可能的组合。然后我对整个数组执行相同操作,即O(n^2)

是否有更优化的解决方案?

1 个答案:

答案 0 :(得分:2)

它可以比O(n ^ 2)更复杂。这里描绘的解决方案是O(n * sqrt(n)* log(n))。

主要想法如下:

  • let(a,b,c)是一个很好的解决方案,一个sqrt(a * b)= c。我们可以将 a 写为a = s * t ^ 2,其中 s 是在 a &中具有奇数指数的素数的乘积#39;主要因素分解。它保证 a 的剩余部分是完美的正方形。由于a * b是完美的正方形,因此b必须是s * k ^ 2的形式。对于每个 a (有O(n)个这样的数字),在从上面的分解中找到 s 之后(这可以在O(log(n))中完成,如它将在下面描述),我们可以将搜索数字 b 限制为b = s * k ^ 2形式,但是只有O(sqrt(n))这样的数字小于 n 。对于每个 a b 这样列举,我们可以在O(1)中测试是否有一个好的 c ,使用您使用的表示在问题中。

上述想法中的一个关键部分是将 a 分解为s * t ^ 2, a 中找到具有奇数幂的素数>分解。

这可以使用预处理步骤来完成,该步骤使用略微修改的Eratosthenes筛来找到{1,2,... n}中每个数字的素因子(但不是它们的幂)。这个修改过的版本不仅会将数字标记为&#34;还不会标记为&#34;当迭代一个素数的倍数时,还会将当前素数附加到当前倍数的因子列表中。该预处理步骤的时间复杂度是n * sum {对于每个素数p <1。 n}(1 / p)= n * log(log(n)) - 有关详细信息,请参阅this

使用预处理的结果,即除去 a 的素数列表,我们可以在O(log(n))中找到具有奇数幂的素数。这是通过将 a 除以列表中的每个素数来实现的,直到它不再被该素数整除。如果我们进行了奇数个除法,那么我们在 s 中使用当前的素数。完成所有分割后,结果将等于1.复杂性为O(log(n)),因为在最坏的情况下,我们总是将初始数除以2(最小的素数),因此需要最多log2(a)步骤达到值1.

主要步骤的复杂性决定了预处理的复杂性,因此这种方法的总体复杂性是O(n * sqrt(n)* log(n))。

备注:在分解a = s * t ^ 2中, s 是带有奇数指数的 a 中素数的乘积,但它们的指数未被使用在 s ie s 只是那些素数的乘积,指数为1)。只有在这种情况下,才能保证 b 的形式应为s * k ^ 2。实际上,由于a * b = c * c,右侧的素因子分解仅使用偶数指数,因此来自 s 的所有素数也应出现在 b 中指数和来自 b 的因子分解的所有其他素数应该具有偶数指数。

扩展以下行:&#34;我们可以将搜索数字 b 限制为 b = s > * k ^ 2,但只有O(sqrt(n))这样的数字小于n&#34;。

让我们考虑一个例子。想象一下,我们有类似 n = 10,000的东西,我们正在寻找具有 a = 360 = 2 ^ 3 * 3 ^ 2 * 5的解决方案。具有奇数指数的素数在 a 中,因子分解为2和5(因此 s = 2 * 5; a = 10 * 6 ^ 2)。

由于 a * b 是一个完美的正方形,它意味着 a * b <素数因子分解中的所有素数/ em>甚至有指数。这意味着那两个素数(2和5)也需要出现在 b 的奇数指数分解中,其余的指数也在 b & #39;主要因子化必须是均匀的。因此 b 的形式为 s * k ^ 2 = 10 * k ^ 2.

所以我们证明 b = 10 * k ^ 2.这很有用,因为我们现在可以枚举所有 b 的值这个形式很快(在O(sqrt(n))。我们只需要考虑 k = 1, k = 2,..., k =(int)sqrt(n / 10)。 k 的较大值导致 b 的值大于 n k 值确定一个 b 值,我们需要验证它。请注意,在验证其中一个 b 值时,应首先检查是否它确实在集合B中,可以在O(1)中完成,并且sqrt(a * b)是否在集合C中,也可以在O(1)中完成。