我有一个从1到n
的整数。我将每个整数随机分配到三组A
,B
和C
(A ∩ B = B ∩ C = C ∩ A = Ø
)中的一组。每个整数都属于一个集合。所以我需要计算(a,b)
元素的所有组合,a ∈ A, b ∈ B
,a,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)
。
是否有更优化的解决方案?
答案 0 :(得分:2)
它可以比O(n ^ 2)更复杂。这里描绘的解决方案是O(n * sqrt(n)* log(n))。
主要想法如下:
上述想法中的一个关键部分是将 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)中完成。